[Merge] Merge from trunk. Revision 6652.
106
Changelog.yaml
@ -4,6 +4,111 @@
|
||||
# for important features/bug fixes.
|
||||
# Also, each release can have new and improved recipes.
|
||||
|
||||
- version: 0.7.24
|
||||
date: 2010-10-17
|
||||
|
||||
new features:
|
||||
- title: "Content server: New interface that allows browsing via categories, similar to the Tag Browser in the calibre interface."
|
||||
description: >
|
||||
"You can access the new interface by going to /browse. So if your calibre content server is available at http://192.168.1.2, use
|
||||
http://192.168.1.2/browse. The new interface requires a fairly modern browser, so no Internet Explorer 6,7."
|
||||
type: major
|
||||
|
||||
- title: "Support for the SNB e-book format, used by the Bambook e-book reader"
|
||||
type: major
|
||||
|
||||
- title: "Driver for the Wifi Kobo"
|
||||
|
||||
- title: "Edit metadata dialog: If metadata is downloaded successfully, set focus to download cover button"
|
||||
|
||||
- title: "News download system: Allow recipes with optional subscriptions"
|
||||
tickets: [7199]
|
||||
|
||||
- title: "Templates: Improve the smarten function"
|
||||
|
||||
- title: "Linux device mounting: Use udisks, if it is available, to mount devices, so that I no longer have to hear bug reports from users using distro packages that have crippled calibre-mount-helper. You can turn off udisks by setting the environment variable CALIBRE_DISABLE_UDISKS=1"
|
||||
|
||||
- title: "Implement Drag'n'drop to tags in user categories"
|
||||
tickets: [7172]
|
||||
|
||||
- title: "Ebook viewer: Add command line option to start in full screen mode"
|
||||
|
||||
- title: "Set completion mode on search boxes to popup completion"
|
||||
|
||||
- title: "Update version of jQuery used in content server and viewer. Required a little hackery in the viewer, hopefully nothing broke"
|
||||
|
||||
bug fixes:
|
||||
- title: "Linux device drivers: Ignore read only partition exported by the device"
|
||||
|
||||
- title: "E-book viewer: Fix scrolling down with mouse wheel not always reaching bottom in windows"
|
||||
|
||||
- title: "Smarten punctuation: Fix bug in handling of comments and <style> tags"
|
||||
|
||||
- title: "EPUB Input: Handle EPUB files with components encoded in an encoding other than UTF-8 correctly, though why anyone would do that is a mystery."
|
||||
tickets: [7196]
|
||||
|
||||
- title: "OS X commandline tools: Decode non-ascii command line arguments correctly"
|
||||
tickets: [6964]
|
||||
|
||||
- title: "MOBI Output: Fix bug that broke conversion of <svg> elements in the input document when the <svg> element was followed by non-whitespace text."
|
||||
tickets: [7083]
|
||||
|
||||
- title: "CHM Input: Fix handling of relative file paths in <img> tags."
|
||||
tickets: [7159]
|
||||
|
||||
- title: "EPUB Output: Fix incorrect format for xml:lang when specifying a sub language"
|
||||
tickets: [7198]
|
||||
|
||||
- title: "EPUB Input: Make parsing of toc.ncx more robust."
|
||||
tickets: [7170]
|
||||
|
||||
- title: "Content server: Fix searching with non-ascii characters on windows"
|
||||
tickets: [5249]
|
||||
|
||||
- title: "Fix average rating calculation for rating datatype in Tag Browser incorrect"
|
||||
|
||||
- title: "Comic Input: Fix image borders becoming yellow on some windows installs"
|
||||
|
||||
- title: "Email sending: Fix sending of email with non ascii chars"
|
||||
tickets: [7137]
|
||||
|
||||
- title: "SONY driver: Fix collections created from series not in order with manual metadata management, if all books in the series are not sent at once"
|
||||
|
||||
- title: "Content server: Apply the search restriction when generating category lists as well"
|
||||
|
||||
- title: "RTF Input: Fix regression in conversion of WMF images on linux at least, maybe on other platforms as wel"
|
||||
|
||||
- title: "Fix isbndb.com metadata downloading sometimes yield a title of Unknown"
|
||||
tickets: [7114]
|
||||
|
||||
- title: "Fix edit metadata dialog causing the hour:minute:seconds of the date column being lost, even when date is not changed"
|
||||
tickets: [7125]
|
||||
|
||||
new recipes:
|
||||
- title: "Revista El Cultural"
|
||||
author: "Jefferson Frantz"
|
||||
|
||||
- title: "Novaya Gazeta"
|
||||
author: "muwa"
|
||||
|
||||
- title: "frazpc.pl"
|
||||
author: "Tomasz Dlugosz"
|
||||
|
||||
- title: "Orsai and Financial Times UK"
|
||||
author: "Darko Miletic"
|
||||
|
||||
- title: "Malayasian Mirror and Rolling Stones"
|
||||
author: "Tony Stegall"
|
||||
|
||||
improved recipes:
|
||||
- Globe and Mail
|
||||
- Business Standard
|
||||
- Miami Herald
|
||||
- El Mercurio
|
||||
- volkskrant.nl
|
||||
- GoComics.com
|
||||
- The New Yorker
|
||||
|
||||
- version: 0.7.23
|
||||
date: 2010-10-08
|
||||
|
||||
@ -51,6 +156,7 @@
|
||||
- title: "CHM input: handle another class of broken CHM files"
|
||||
tickets: [7058]
|
||||
|
||||
- title: "Make calibre worker processes use the same temp directory as the calibre GUI"
|
||||
|
||||
new recipes:
|
||||
- title: "Communications of the Association for Computing Machinery"
|
||||
|
440
resources/content_server/browse/browse.css
Normal file
@ -0,0 +1,440 @@
|
||||
body {
|
||||
background-color: #fffcf2;
|
||||
font-family: sans-serif;
|
||||
margin: 0 0 0 0;
|
||||
padding: 0 0 0 0;
|
||||
}
|
||||
|
||||
#container {
|
||||
max-width: 1000px;
|
||||
min-width: 400px;
|
||||
min-height: 230px;
|
||||
background-color: #F6F3E9;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
-moz-box-shadow: 5px 5px 5px #ccc;
|
||||
-webkit-box-shadow: 5px 5px 5px #ccc;
|
||||
box-shadow: 5px 5px 5px #ccc;
|
||||
}
|
||||
|
||||
#header {
|
||||
height: 130px;
|
||||
background: url('/static/logo.png') no-repeat scroll left top #39322b;
|
||||
}
|
||||
|
||||
#content {
|
||||
max-width: 1000px;
|
||||
min-width: 400px;
|
||||
min-height: 100px;
|
||||
}
|
||||
|
||||
#main {
|
||||
padding-left: 0.5em;
|
||||
padding-right: 0.5em;
|
||||
|
||||
}
|
||||
|
||||
#footer {
|
||||
font-size: small;
|
||||
color: #a6a399;
|
||||
text-align: right;
|
||||
margin-right: 30px;
|
||||
}
|
||||
|
||||
/* Header {{{ */
|
||||
#header .area {
|
||||
width: 300px;
|
||||
height: 130px;
|
||||
position: relative;
|
||||
margin-left: 230px;
|
||||
color: white;
|
||||
font-size: xx-large;
|
||||
font-family: monospace;
|
||||
overflow: hidden;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
#header .bubble {
|
||||
position: absolute;
|
||||
left: 93px;
|
||||
top: 21px;
|
||||
width: 135px;
|
||||
height: 84px;
|
||||
display: table;
|
||||
}
|
||||
|
||||
#header .bubble p {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#header a {
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
text-shadow: #27211b 2px 2px 2px;
|
||||
}
|
||||
|
||||
#header a:hover {
|
||||
background-color: #39a9cf;
|
||||
-moz-border-radius: 5px;
|
||||
-webkit-border-radius: 5px;
|
||||
text-shadow: #27211b 1px 1px 1px;
|
||||
-moz-box-shadow: 5px 5px 5px #222;
|
||||
-webkit-box-shadow: 5px 5px 5px #222;
|
||||
box-shadow: 5px 5px 5px #222;
|
||||
|
||||
}
|
||||
|
||||
#nav-container {
|
||||
position: relative;
|
||||
height: 130px;
|
||||
top: -130px;
|
||||
left: 0%;
|
||||
}
|
||||
|
||||
ul#primary-nav {
|
||||
display: block;
|
||||
margin-right: 60px;
|
||||
text-align: right;
|
||||
margin-top: 90px;
|
||||
line-height: 20px;
|
||||
cursor: default;
|
||||
position: relative;
|
||||
top: -2ex;
|
||||
}
|
||||
|
||||
ul#primary-nav li {
|
||||
display: inline;
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
ul#primary-nav li a {
|
||||
padding: 6px;
|
||||
font-variant: small-caps;
|
||||
font-weight: bold;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
|
||||
#donate {
|
||||
display: block;
|
||||
width: 200px;
|
||||
height: 38px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
top: -260px;
|
||||
left: 65%;
|
||||
}
|
||||
|
||||
#calibre-home-link {
|
||||
position: relative;
|
||||
top: -298px;
|
||||
left: 0%;
|
||||
z-index: 2;
|
||||
height: 130px;
|
||||
width: 230px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
h2.library_name {
|
||||
font-family: monospace;
|
||||
font-size: 50px;
|
||||
font-weight: normal;
|
||||
color: white;
|
||||
margin-left: 250px;
|
||||
padding-top: 40px;
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
|
||||
/* Sort select {{{ */
|
||||
|
||||
.sort_select {
|
||||
float: left;
|
||||
margin-left: 1em;
|
||||
margin-top: 2ex;
|
||||
max-height: 2.75em;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sort_select label {
|
||||
font-size: medium;
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
|
||||
/* Search bar {{{ */
|
||||
|
||||
#search_box {
|
||||
float: right;
|
||||
margin-right: 1em;
|
||||
margin-top: 2ex;
|
||||
max-height: 2.75em;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#search_box .ui-button {
|
||||
padding: 0.25em;
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
|
||||
/* Top level {{{ */
|
||||
.toplevel ul {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.toplevel li {
|
||||
margin: 0.75em;
|
||||
padding: 0.75em;
|
||||
cursor: pointer;
|
||||
font-size: larger;
|
||||
float: left;
|
||||
border-radius: 15px;
|
||||
-moz-border-radius: 15px;
|
||||
-webkit-border-radius: 15px;
|
||||
display: inline;
|
||||
width: 250px;
|
||||
height: 48px;
|
||||
overflow: hidden;
|
||||
|
||||
}
|
||||
|
||||
.toplevel li img {
|
||||
vertical-align: middle;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
.toplevel li:hover {
|
||||
background-color: #d6d3c9;
|
||||
font-weight: bold;
|
||||
-moz-box-shadow: 5px 5px 5px #ccc;
|
||||
-webkit-box-shadow: 5px 5px 5px #ccc;
|
||||
box-shadow: 5px 5px 5px #ccc;
|
||||
|
||||
}
|
||||
|
||||
.toplevel li span.url { display: none }
|
||||
.toplevel li span.label {
|
||||
}
|
||||
|
||||
|
||||
/* }}} */
|
||||
|
||||
/* Category {{{ */
|
||||
.category > div.category-container {
|
||||
width: 100%;
|
||||
margin-top: 1ex;
|
||||
margin-bottom: 1ex;
|
||||
display: table;
|
||||
}
|
||||
|
||||
.category div.category-item {
|
||||
display: table-row;
|
||||
}
|
||||
|
||||
.category div.category-item > div {
|
||||
padding: 0.75em;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
display: table-cell;
|
||||
}
|
||||
|
||||
.category div.category-name { font-weight: bold }
|
||||
|
||||
.category div.category-item:hover > div {
|
||||
background-color: #d6d3c9;
|
||||
-moz-box-shadow: 5px 5px 5px #ccc;
|
||||
-webkit-box-shadow: 5px 5px 5px #ccc;
|
||||
box-shadow: 5px 5px 5px #ccc;
|
||||
border-radius: 15px;
|
||||
-moz-border-radius: 15px;
|
||||
-webkit-border-radius: 15px;
|
||||
|
||||
}
|
||||
|
||||
.category div.category-item span.href { display: none }
|
||||
|
||||
#groups span.load_href { display: none }
|
||||
|
||||
#groups h3 {
|
||||
font-weight: bold;
|
||||
margin-top: 1ex;
|
||||
padding-left: 30px;
|
||||
padding-top: 0.5ex;
|
||||
padding-bottom: 0.5ex;
|
||||
}
|
||||
|
||||
#groups h3 span {
|
||||
font-weight: normal
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
.details .right .formats a {
|
||||
color: blue;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.details .right .formats a:hover {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.details .field {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.details .comment {
|
||||
margin-left: 1em;
|
||||
overflow: auto;
|
||||
max-height: 50%;
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
|
99
resources/content_server/browse/browse.html
Normal file
@ -0,0 +1,99 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<title>..:: calibre library ::.. {title}</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=100" />
|
||||
<link rel="icon" type="image/x-icon" href="http://calibre-ebook.com/favicon.ico" />
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/static/browse/browse.css" />
|
||||
<link type="text/css" href="/static/jquery_ui/css/humanity-custom/jquery-ui-1.8.5.custom.css" rel="stylesheet" />
|
||||
<link rel="stylesheet" type="text/css" href="/static/jquery.multiselect.css" />
|
||||
|
||||
<script type="text/javascript" src="/static/jquery.js"></script>
|
||||
<script type="text/javascript" src="/static/jquery.corner.js"></script>
|
||||
|
||||
<script type="text/javascript"
|
||||
src="/static/jquery_ui/js/jquery-ui-1.8.5.custom.min.js"></script>
|
||||
<script type="text/javascript"
|
||||
src="/static/jquery.multiselect.min.js"></script>
|
||||
|
||||
|
||||
<script type="text/javascript" src="/static/browse/browse.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
var sort_cookie_name = "{sort_cookie_name}";
|
||||
var sort_select_label = "{sort_select_label}";
|
||||
$(document).ready(function() {{
|
||||
init();
|
||||
{script}
|
||||
}});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container">
|
||||
|
||||
<!-- Header -->
|
||||
<div id="header">
|
||||
<div class="area">
|
||||
<div class="bubble">
|
||||
<p><a href="/browse" title="Return to top level"
|
||||
>→ home ←</a></p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="nav-container">
|
||||
<ul id="primary-nav">
|
||||
<li><a id="nav-mobile" href="/mobile" title="A version of this website suited for mobile browsers">Mobile</a></li>
|
||||
|
||||
<li><a id="nav-demo" href="/old" title="The old version of this webiste">Old</a></li>
|
||||
<li><a id="nav-download" href="/opds" title="An OPDS feed based version of this website, used in special purpose applications">Feed</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<form id="donate" action="https://www.paypal.com/cgi-bin/webscr"
|
||||
method="post" title="Donate to support the development of calibre">
|
||||
<div>
|
||||
<input type="hidden" name="cmd" value="_s-xclick"></input>
|
||||
<input type="hidden" name="hosted_button_id" value="3028915"></input>
|
||||
<input type="image"
|
||||
src="http://calibre-ebook.com/site_media//img/button-donate.png"
|
||||
name="submit"></input>
|
||||
<img alt="" src="https://www.paypal.com/en_US/i/scr/pixel.gif"
|
||||
width="1" height="1"></img>
|
||||
</div>
|
||||
</form>
|
||||
<div id="calibre-home-link" title="Go to the calibre website"></div>
|
||||
</div>
|
||||
<!-- End header -->
|
||||
|
||||
<div id="content">
|
||||
<div class="sort_select">
|
||||
<label>{sort_select_label}</label>
|
||||
<select id="sort_combobox">
|
||||
{sort_select_options}
|
||||
</select>
|
||||
</div>
|
||||
<div id="search_box">
|
||||
<form name="search_form" action="/browse/search" method="get" accept-charset="UTF-8">
|
||||
<input value="{initial_search}" type="text" title="Search" name="query"
|
||||
class="search_input" />
|
||||
<input type="submit" value="Search" title="Search" alt="Search" />
|
||||
</form>
|
||||
</div>
|
||||
<div> </div>
|
||||
<div> </div>
|
||||
<div> </div>
|
||||
|
||||
<div id="main">
|
||||
{main}
|
||||
</div>
|
||||
<div id="footer">
|
||||
[{library_path}] Created by Kovid Goyal
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="book_details_dialog"></div>
|
||||
</body>
|
||||
</html>
|
289
resources/content_server/browse/browse.js
Normal file
@ -0,0 +1,289 @@
|
||||
|
||||
// Cookies {{{
|
||||
/**
|
||||
* Create a cookie with the given name and value and other optional parameters.
|
||||
*
|
||||
* @example $.cookie('the_cookie', 'the_value');
|
||||
* @desc Set the value of a cookie.
|
||||
* @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true });
|
||||
* @desc Create a cookie with all available options.
|
||||
* @example $.cookie('the_cookie', 'the_value');
|
||||
* @desc Create a session cookie.
|
||||
* @example $.cookie('the_cookie', null);
|
||||
* @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain
|
||||
* used when the cookie was set.
|
||||
*
|
||||
* @param String name The name of the cookie.
|
||||
* @param String value The value of the cookie.
|
||||
* @param Object options An object literal containing key/value pairs to provide optional cookie attributes.
|
||||
* @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object.
|
||||
* If a negative value is specified (e.g. a date in the past), the cookie will be deleted.
|
||||
* If set to null or omitted, the cookie will be a session cookie and will not be retained
|
||||
* when the the browser exits.
|
||||
* @option String path The value of the path atribute of the cookie (default: path of page that created the cookie).
|
||||
* @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie).
|
||||
* @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will
|
||||
* require a secure protocol (like HTTPS).
|
||||
* @type undefined
|
||||
*
|
||||
* @name $.cookie
|
||||
* @cat Plugins/Cookie
|
||||
* @author Klaus Hartl/klaus.hartl@stilbuero.de
|
||||
*/
|
||||
|
||||
function cookie(name, value, options) {
|
||||
if (typeof value != 'undefined') { // name and value given, set cookie
|
||||
options = options || {};
|
||||
if (value === null) {
|
||||
value = '';
|
||||
options.expires = -1;
|
||||
}
|
||||
var expires = '';
|
||||
if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
|
||||
var date;
|
||||
if (typeof options.expires == 'number') {
|
||||
date = new Date();
|
||||
date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
|
||||
} else {
|
||||
date = options.expires;
|
||||
}
|
||||
expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
|
||||
}
|
||||
// CAUTION: Needed to parenthesize options.path and options.domain
|
||||
// in the following expressions, otherwise they evaluate to undefined
|
||||
// in the packed version for some reason...
|
||||
var path = options.path ? '; path=' + (options.path) : '';
|
||||
var domain = options.domain ? '; domain=' + (options.domain) : '';
|
||||
var secure = options.secure ? '; secure' : '';
|
||||
document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
|
||||
} else { // only name given, get cookie
|
||||
var cookieValue = null;
|
||||
if (document.cookie && document.cookie != '') {
|
||||
var cookies = document.cookie.split(';');
|
||||
for (var i = 0; i < cookies.length; i++) {
|
||||
var cookie = jQuery.trim(cookies[i]);
|
||||
// Does this cookie string begin with the name we want?
|
||||
if (cookie.substring(0, name.length + 1) == (name + '=')) {
|
||||
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return cookieValue;
|
||||
}
|
||||
};
|
||||
|
||||
// }}}
|
||||
|
||||
// Sort {{{
|
||||
|
||||
function init_sort_combobox() {
|
||||
$("#sort_combobox").multiselect({
|
||||
multiple: false,
|
||||
header: sort_select_label,
|
||||
noneSelectedText: sort_select_label,
|
||||
selectedList: 1,
|
||||
click: function(event, ui){
|
||||
$(this).multiselect("close");
|
||||
cookie(sort_cookie_name, ui.value);
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
function init() {
|
||||
$("#container").corner("30px");
|
||||
$("#header").corner("30px");
|
||||
$("#calibre-home-link").click(function() { window.location = "http://calibre-ebook.com"; });
|
||||
|
||||
init_sort_combobox();
|
||||
|
||||
$("#search_box input:submit").button();
|
||||
}
|
||||
|
||||
// Top-level feed {{{
|
||||
|
||||
function toplevel_layout() {
|
||||
var last = $(".toplevel li").last();
|
||||
var title = $('.toplevel h3').first();
|
||||
var bottom = last.position().top + last.height() - title.position().top;
|
||||
$("#main").height(Math.max(200, bottom));
|
||||
}
|
||||
|
||||
function toplevel() {
|
||||
$(".sort_select").hide();
|
||||
|
||||
$(".toplevel li").click(function() {
|
||||
var href = $(this).children("span.url").text();
|
||||
window.location = href;
|
||||
});
|
||||
|
||||
toplevel_layout();
|
||||
$(window).resize(toplevel_layout);
|
||||
|
||||
}
|
||||
// }}}
|
||||
|
||||
function render_error(msg) {
|
||||
return '<div class="ui-widget"><div class="ui-state-error ui-corner-all" style="padding: 0pt 0.7em"><p><span class="ui-icon ui-icon-alert" style="float: left; margin-right: 0.3em"> </span><strong>Error: </strong>'+msg+"</p></div></div>"
|
||||
}
|
||||
|
||||
// Category feed {{{
|
||||
|
||||
function category_clicked() {
|
||||
var href = $(this).find("span.href").html();
|
||||
window.location = href;
|
||||
}
|
||||
|
||||
function category() {
|
||||
$(".category .category-item").click(category_clicked);
|
||||
|
||||
$(".category a.navlink").button();
|
||||
|
||||
$("#groups").accordion({
|
||||
collapsible: true,
|
||||
active: false,
|
||||
autoHeight: false,
|
||||
clearStyle: true,
|
||||
header: "h3",
|
||||
|
||||
change: function(event, ui) {
|
||||
if (ui.newContent) {
|
||||
var href = ui.newContent.children("span.load_href").html();
|
||||
ui.newContent.children(".loading").show();
|
||||
if (href) {
|
||||
$.ajax({
|
||||
url:href,
|
||||
data:{'sort':cookie(sort_cookie_name)},
|
||||
success: function(data) {
|
||||
this.children(".loaded").html(data);
|
||||
this.children(".loaded").show();
|
||||
this.children(".loading").hide();
|
||||
this.find('.category-item').click(category_clicked);
|
||||
},
|
||||
context: ui.newContent,
|
||||
dataType: "json",
|
||||
timeout: 600000, //milliseconds (10 minutes)
|
||||
error: function(xhr, stat, err) {
|
||||
this.children(".loaded").html(render_error(stat));
|
||||
this.children(".loaded").show();
|
||||
this.children(".loading").hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
// }}}
|
||||
|
||||
// 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 hidesort() {$("#content > .sort_select").hide();}
|
||||
|
||||
function booklist(hide_sort) {
|
||||
if (hide_sort) hidesort();
|
||||
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…</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');
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
function book() {
|
||||
hidesort();
|
||||
$('.details .left img').load(function() {
|
||||
var img = $('.details .left img');
|
||||
var height = $('#main').height();
|
||||
height = Math.max(height, img.height() + 100);
|
||||
$('#main').height(height);
|
||||
});
|
||||
}
|
10
resources/content_server/browse/details.html
Normal 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>
|
20
resources/content_server/browse/summary.html
Normal file
@ -0,0 +1,20 @@
|
||||
<div id="summary_{id}" class="summary">
|
||||
<div class="left">
|
||||
<img alt="Cover of {title}" src="/get/thumb_90_120/{id}" />
|
||||
{get_button}
|
||||
</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>
|
||||
<a href="/browse/book/{id}" title="{permalink_tt}">{permalink}</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>
|
@ -15,7 +15,7 @@
|
||||
</div>
|
||||
|
||||
<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 type="image" src="/static/btn_search_box.png" width="27" height="24" id="go" alt="Search" title="Search" />
|
||||
</form>
|
||||
|
247
resources/content_server/jquery.corner.js
Normal file
@ -0,0 +1,247 @@
|
||||
/*!
|
||||
* jQuery corner plugin: simple corner rounding
|
||||
* Examples and documentation at: http://jquery.malsup.com/corner/
|
||||
* version 2.11 (15-JUN-2010)
|
||||
* Requires jQuery v1.3.2 or later
|
||||
* Dual licensed under the MIT and GPL licenses:
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
* http://www.gnu.org/licenses/gpl.html
|
||||
* Authors: Dave Methvin and Mike Alsup
|
||||
*/
|
||||
|
||||
/**
|
||||
* corner() takes a single string argument: $('#myDiv').corner("effect corners width")
|
||||
*
|
||||
* effect: name of the effect to apply, such as round, bevel, notch, bite, etc (default is round).
|
||||
* corners: one or more of: top, bottom, tr, tl, br, or bl. (default is all corners)
|
||||
* width: width of the effect; in the case of rounded corners this is the radius.
|
||||
* specify this value using the px suffix such as 10px (yes, it must be pixels).
|
||||
*/
|
||||
;(function($) {
|
||||
|
||||
var style = document.createElement('div').style,
|
||||
moz = style['MozBorderRadius'] !== undefined,
|
||||
webkit = style['WebkitBorderRadius'] !== undefined,
|
||||
radius = style['borderRadius'] !== undefined || style['BorderRadius'] !== undefined,
|
||||
mode = document.documentMode || 0,
|
||||
noBottomFold = $.browser.msie && (($.browser.version < 8 && !mode) || mode < 8),
|
||||
|
||||
expr = $.browser.msie && (function() {
|
||||
var div = document.createElement('div');
|
||||
try { div.style.setExpression('width','0+0'); div.style.removeExpression('width'); }
|
||||
catch(e) { return false; }
|
||||
return true;
|
||||
})();
|
||||
|
||||
$.support = $.support || {};
|
||||
$.support.borderRadius = moz || webkit || radius; // so you can do: if (!$.support.borderRadius) $('#myDiv').corner();
|
||||
|
||||
function sz(el, p) {
|
||||
return parseInt($.css(el,p))||0;
|
||||
};
|
||||
function hex2(s) {
|
||||
var s = parseInt(s).toString(16);
|
||||
return ( s.length < 2 ) ? '0'+s : s;
|
||||
};
|
||||
function gpc(node) {
|
||||
while(node) {
|
||||
var v = $.css(node,'backgroundColor'), rgb;
|
||||
if (v && v != 'transparent' && v != 'rgba(0, 0, 0, 0)') {
|
||||
if (v.indexOf('rgb') >= 0) {
|
||||
rgb = v.match(/\d+/g);
|
||||
return '#'+ hex2(rgb[0]) + hex2(rgb[1]) + hex2(rgb[2]);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
if (node.nodeName.toLowerCase() == 'html')
|
||||
break;
|
||||
node = node.parentNode; // keep walking if transparent
|
||||
}
|
||||
return '#ffffff';
|
||||
};
|
||||
|
||||
function getWidth(fx, i, width) {
|
||||
switch(fx) {
|
||||
case 'round': return Math.round(width*(1-Math.cos(Math.asin(i/width))));
|
||||
case 'cool': return Math.round(width*(1+Math.cos(Math.asin(i/width))));
|
||||
case 'sharp': return Math.round(width*(1-Math.cos(Math.acos(i/width))));
|
||||
case 'bite': return Math.round(width*(Math.cos(Math.asin((width-i-1)/width))));
|
||||
case 'slide': return Math.round(width*(Math.atan2(i,width/i)));
|
||||
case 'jut': return Math.round(width*(Math.atan2(width,(width-i-1))));
|
||||
case 'curl': return Math.round(width*(Math.atan(i)));
|
||||
case 'tear': return Math.round(width*(Math.cos(i)));
|
||||
case 'wicked': return Math.round(width*(Math.tan(i)));
|
||||
case 'long': return Math.round(width*(Math.sqrt(i)));
|
||||
case 'sculpt': return Math.round(width*(Math.log((width-i-1),width)));
|
||||
case 'dogfold':
|
||||
case 'dog': return (i&1) ? (i+1) : width;
|
||||
case 'dog2': return (i&2) ? (i+1) : width;
|
||||
case 'dog3': return (i&3) ? (i+1) : width;
|
||||
case 'fray': return (i%2)*width;
|
||||
case 'notch': return width;
|
||||
case 'bevelfold':
|
||||
case 'bevel': return i+1;
|
||||
}
|
||||
};
|
||||
|
||||
$.fn.corner = function(options) {
|
||||
// in 1.3+ we can fix mistakes with the ready state
|
||||
if (this.length == 0) {
|
||||
if (!$.isReady && this.selector) {
|
||||
var s = this.selector, c = this.context;
|
||||
$(function() {
|
||||
$(s,c).corner(options);
|
||||
});
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
return this.each(function(index){
|
||||
var $this = $(this),
|
||||
// meta values override options
|
||||
o = [$this.attr($.fn.corner.defaults.metaAttr) || '', options || ''].join(' ').toLowerCase(),
|
||||
keep = /keep/.test(o), // keep borders?
|
||||
cc = ((o.match(/cc:(#[0-9a-f]+)/)||[])[1]), // corner color
|
||||
sc = ((o.match(/sc:(#[0-9a-f]+)/)||[])[1]), // strip color
|
||||
width = parseInt((o.match(/(\d+)px/)||[])[1]) || 10, // corner width
|
||||
re = /round|bevelfold|bevel|notch|bite|cool|sharp|slide|jut|curl|tear|fray|wicked|sculpt|long|dog3|dog2|dogfold|dog/,
|
||||
fx = ((o.match(re)||['round'])[0]),
|
||||
fold = /dogfold|bevelfold/.test(o),
|
||||
edges = { T:0, B:1 },
|
||||
opts = {
|
||||
TL: /top|tl|left/.test(o), TR: /top|tr|right/.test(o),
|
||||
BL: /bottom|bl|left/.test(o), BR: /bottom|br|right/.test(o)
|
||||
},
|
||||
// vars used in func later
|
||||
strip, pad, cssHeight, j, bot, d, ds, bw, i, w, e, c, common, $horz;
|
||||
|
||||
if ( !opts.TL && !opts.TR && !opts.BL && !opts.BR )
|
||||
opts = { TL:1, TR:1, BL:1, BR:1 };
|
||||
|
||||
// support native rounding
|
||||
if ($.fn.corner.defaults.useNative && fx == 'round' && (radius || moz || webkit) && !cc && !sc) {
|
||||
if (opts.TL)
|
||||
$this.css(radius ? 'border-top-left-radius' : moz ? '-moz-border-radius-topleft' : '-webkit-border-top-left-radius', width + 'px');
|
||||
if (opts.TR)
|
||||
$this.css(radius ? 'border-top-right-radius' : moz ? '-moz-border-radius-topright' : '-webkit-border-top-right-radius', width + 'px');
|
||||
if (opts.BL)
|
||||
$this.css(radius ? 'border-bottom-left-radius' : moz ? '-moz-border-radius-bottomleft' : '-webkit-border-bottom-left-radius', width + 'px');
|
||||
if (opts.BR)
|
||||
$this.css(radius ? 'border-bottom-right-radius' : moz ? '-moz-border-radius-bottomright' : '-webkit-border-bottom-right-radius', width + 'px');
|
||||
return;
|
||||
}
|
||||
|
||||
strip = document.createElement('div');
|
||||
$(strip).css({
|
||||
overflow: 'hidden',
|
||||
height: '1px',
|
||||
minHeight: '1px',
|
||||
fontSize: '1px',
|
||||
backgroundColor: sc || 'transparent',
|
||||
borderStyle: 'solid'
|
||||
});
|
||||
|
||||
pad = {
|
||||
T: parseInt($.css(this,'paddingTop'))||0, R: parseInt($.css(this,'paddingRight'))||0,
|
||||
B: parseInt($.css(this,'paddingBottom'))||0, L: parseInt($.css(this,'paddingLeft'))||0
|
||||
};
|
||||
|
||||
if (typeof this.style.zoom != undefined) this.style.zoom = 1; // force 'hasLayout' in IE
|
||||
if (!keep) this.style.border = 'none';
|
||||
strip.style.borderColor = cc || gpc(this.parentNode);
|
||||
cssHeight = $(this).outerHeight();
|
||||
|
||||
for (j in edges) {
|
||||
bot = edges[j];
|
||||
// only add stips if needed
|
||||
if ((bot && (opts.BL || opts.BR)) || (!bot && (opts.TL || opts.TR))) {
|
||||
strip.style.borderStyle = 'none '+(opts[j+'R']?'solid':'none')+' none '+(opts[j+'L']?'solid':'none');
|
||||
d = document.createElement('div');
|
||||
$(d).addClass('jquery-corner');
|
||||
ds = d.style;
|
||||
|
||||
bot ? this.appendChild(d) : this.insertBefore(d, this.firstChild);
|
||||
|
||||
if (bot && cssHeight != 'auto') {
|
||||
if ($.css(this,'position') == 'static')
|
||||
this.style.position = 'relative';
|
||||
ds.position = 'absolute';
|
||||
ds.bottom = ds.left = ds.padding = ds.margin = '0';
|
||||
if (expr)
|
||||
ds.setExpression('width', 'this.parentNode.offsetWidth');
|
||||
else
|
||||
ds.width = '100%';
|
||||
}
|
||||
else if (!bot && $.browser.msie) {
|
||||
if ($.css(this,'position') == 'static')
|
||||
this.style.position = 'relative';
|
||||
ds.position = 'absolute';
|
||||
ds.top = ds.left = ds.right = ds.padding = ds.margin = '0';
|
||||
|
||||
// fix ie6 problem when blocked element has a border width
|
||||
if (expr) {
|
||||
bw = sz(this,'borderLeftWidth') + sz(this,'borderRightWidth');
|
||||
ds.setExpression('width', 'this.parentNode.offsetWidth - '+bw+'+ "px"');
|
||||
}
|
||||
else
|
||||
ds.width = '100%';
|
||||
}
|
||||
else {
|
||||
ds.position = 'relative';
|
||||
ds.margin = !bot ? '-'+pad.T+'px -'+pad.R+'px '+(pad.T-width)+'px -'+pad.L+'px' :
|
||||
(pad.B-width)+'px -'+pad.R+'px -'+pad.B+'px -'+pad.L+'px';
|
||||
}
|
||||
|
||||
for (i=0; i < width; i++) {
|
||||
w = Math.max(0,getWidth(fx,i, width));
|
||||
e = strip.cloneNode(false);
|
||||
e.style.borderWidth = '0 '+(opts[j+'R']?w:0)+'px 0 '+(opts[j+'L']?w:0)+'px';
|
||||
bot ? d.appendChild(e) : d.insertBefore(e, d.firstChild);
|
||||
}
|
||||
|
||||
if (fold && $.support.boxModel) {
|
||||
if (bot && noBottomFold) continue;
|
||||
for (c in opts) {
|
||||
if (!opts[c]) continue;
|
||||
if (bot && (c == 'TL' || c == 'TR')) continue;
|
||||
if (!bot && (c == 'BL' || c == 'BR')) continue;
|
||||
|
||||
common = { position: 'absolute', border: 'none', margin: 0, padding: 0, overflow: 'hidden', backgroundColor: strip.style.borderColor };
|
||||
$horz = $('<div/>').css(common).css({ width: width + 'px', height: '1px' });
|
||||
switch(c) {
|
||||
case 'TL': $horz.css({ bottom: 0, left: 0 }); break;
|
||||
case 'TR': $horz.css({ bottom: 0, right: 0 }); break;
|
||||
case 'BL': $horz.css({ top: 0, left: 0 }); break;
|
||||
case 'BR': $horz.css({ top: 0, right: 0 }); break;
|
||||
}
|
||||
d.appendChild($horz[0]);
|
||||
|
||||
var $vert = $('<div/>').css(common).css({ top: 0, bottom: 0, width: '1px', height: width + 'px' });
|
||||
switch(c) {
|
||||
case 'TL': $vert.css({ left: width }); break;
|
||||
case 'TR': $vert.css({ right: width }); break;
|
||||
case 'BL': $vert.css({ left: width }); break;
|
||||
case 'BR': $vert.css({ right: width }); break;
|
||||
}
|
||||
d.appendChild($vert[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$.fn.uncorner = function() {
|
||||
if (radius || moz || webkit)
|
||||
this.css(radius ? 'border-radius' : moz ? '-moz-border-radius' : '-webkit-border-radius', 0);
|
||||
$('div.jquery-corner', this).remove();
|
||||
return this;
|
||||
};
|
||||
|
||||
// expose options
|
||||
$.fn.corner.defaults = {
|
||||
useNative: true, // true if plugin should attempt to use native browser support for border radius rounding
|
||||
metaAttr: 'data-corner' // name of meta attribute to use for options
|
||||
};
|
||||
|
||||
})(jQuery);
|
7895
resources/content_server/jquery.js
vendored
21
resources/content_server/jquery.multiselect.css
Normal file
@ -0,0 +1,21 @@
|
||||
.ui-multiselect { padding:2px 0 2px 4px; text-align:left }
|
||||
.ui-multiselect span.ui-icon { float:right }
|
||||
|
||||
.ui-multiselect-header { margin-bottom:3px; padding:3px 0 3px 4px }
|
||||
.ui-multiselect-header ul { font-size:0.9em }
|
||||
.ui-multiselect-header ul li { float:left; padding:0 10px 0 0 }
|
||||
.ui-multiselect-header a { text-decoration:none }
|
||||
.ui-multiselect-header a:hover { text-decoration:underline }
|
||||
.ui-multiselect-header span.ui-icon { float:left }
|
||||
.ui-multiselect-header li.ui-multiselect-close { float:right; text-align:right; padding-right:0 }
|
||||
|
||||
.ui-multiselect-menu { display:none; padding:3px; position:absolute; z-index:10000 }
|
||||
.ui-multiselect-checkboxes { position:relative /* fixes bug in IE6/7 */; overflow-y:scroll }
|
||||
.ui-multiselect-checkboxes label { cursor:default; display:block; border:1px solid transparent; padding:3px 1px }
|
||||
.ui-multiselect-checkboxes label input { position:relative; top:1px }
|
||||
.ui-multiselect-checkboxes li { clear:both; font-size:0.9em; padding-right:3px }
|
||||
.ui-multiselect-checkboxes li.ui-multiselect-optgroup-label { text-align:center; font-weight:bold; border-bottom:1px solid }
|
||||
.ui-multiselect-checkboxes li.ui-multiselect-optgroup-label a { display:block; padding:3px; margin:1px 0; text-decoration:none }
|
||||
|
||||
/* remove label borders in IE6 because IE6 does not support transparency */
|
||||
* html .ui-multiselect-checkboxes label { border:none }
|
16
resources/content_server/jquery.multiselect.min.js
vendored
Normal file
After Width: | Height: | Size: 180 B |
After Width: | Height: | Size: 123 B |
After Width: | Height: | Size: 130 B |
After Width: | Height: | Size: 161 B |
After Width: | Height: | Size: 103 B |
After Width: | Height: | Size: 114 B |
After Width: | Height: | Size: 147 B |
After Width: | Height: | Size: 113 B |
After Width: | Height: | Size: 5.2 KiB |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 5.2 KiB |
After Width: | Height: | Size: 5.2 KiB |
After Width: | Height: | Size: 4.3 KiB |
390
resources/content_server/jquery_ui/css/humanity-custom/jquery-ui-1.8.5.custom.css
vendored
Normal file
@ -0,0 +1,390 @@
|
||||
/*
|
||||
* jQuery UI CSS Framework @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/Theming/API
|
||||
*/
|
||||
|
||||
/* Layout helpers
|
||||
----------------------------------*/
|
||||
.ui-helper-hidden { display: none; }
|
||||
.ui-helper-hidden-accessible { position: absolute; left: -99999999px; }
|
||||
.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
|
||||
.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
|
||||
.ui-helper-clearfix { display: inline-block; }
|
||||
/* required comment for clearfix to work in Opera \*/
|
||||
* html .ui-helper-clearfix { height:1%; }
|
||||
.ui-helper-clearfix { display:block; }
|
||||
/* end clearfix */
|
||||
.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
|
||||
|
||||
|
||||
/* Interaction Cues
|
||||
----------------------------------*/
|
||||
.ui-state-disabled { cursor: default !important; }
|
||||
|
||||
|
||||
/* Icons
|
||||
----------------------------------*/
|
||||
|
||||
/* states and images */
|
||||
.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
|
||||
|
||||
|
||||
/* Misc visuals
|
||||
----------------------------------*/
|
||||
|
||||
/* Overlays */
|
||||
.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
|
||||
|
||||
|
||||
/*
|
||||
* jQuery UI CSS Framework @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/Theming/API
|
||||
*
|
||||
* 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
|
||||
----------------------------------*/
|
||||
.ui-widget { font-family: Verdana,Arial,sans-serif; font-size: 1.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-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 a { color: #1e1b1d; }
|
||||
.ui-widget-header { border: 1px solid #d49768; background: #cb842e url(images/ui-bg_glass_25_cb842e_1x400.png) 50% 50% repeat-x; color: #ffffff; font-weight: bold; }
|
||||
.ui-widget-header a { color: #ffffff; }
|
||||
|
||||
/* Interaction states
|
||||
----------------------------------*/
|
||||
.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #cdc3b7; background: #ede4d4 url(images/ui-bg_glass_70_ede4d4_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #3f3731; }
|
||||
.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #3f3731; text-decoration: none; }
|
||||
.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #f5ad66; background: #f5f0e5 url(images/ui-bg_glass_100_f5f0e5_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #a46313; }
|
||||
.ui-state-hover a, .ui-state-hover a:hover { color: #a46313; text-decoration: none; }
|
||||
.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #e0cfc2; background: #f4f0ec url(images/ui-bg_highlight-hard_100_f4f0ec_1x100.png) 50% 50% repeat-x; font-weight: normal; color: #b85700; }
|
||||
.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #b85700; text-decoration: none; }
|
||||
.ui-widget :active { outline: none; }
|
||||
|
||||
/* Interaction Cues
|
||||
----------------------------------*/
|
||||
.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #d9bb73; background: #f5f5b5 url(images/ui-bg_highlight-hard_75_f5f5b5_1x100.png) 50% top repeat-x; color: #060200; }
|
||||
.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #060200; }
|
||||
.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #f8893f; background: #fee4bd url(images/ui-bg_highlight-hard_65_fee4bd_1x100.png) 50% top repeat-x; color: #592003; }
|
||||
.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #592003; }
|
||||
.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #592003; }
|
||||
.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
|
||||
.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
|
||||
.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
|
||||
|
||||
/* Icons
|
||||
----------------------------------*/
|
||||
|
||||
/* states and images */
|
||||
.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_c47a23_256x240.png); }
|
||||
.ui-widget-content .ui-icon {background-image: url(images/ui-icons_c47a23_256x240.png); }
|
||||
.ui-widget-header .ui-icon {background-image: url(images/ui-icons_ffffff_256x240.png); }
|
||||
.ui-state-default .ui-icon { background-image: url(images/ui-icons_f08000_256x240.png); }
|
||||
.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_f08000_256x240.png); }
|
||||
.ui-state-active .ui-icon {background-image: url(images/ui-icons_f35f07_256x240.png); }
|
||||
.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_cb672b_256x240.png); }
|
||||
.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_ff7519_256x240.png); }
|
||||
|
||||
/* positioning */
|
||||
.ui-icon-carat-1-n { background-position: 0 0; }
|
||||
.ui-icon-carat-1-ne { background-position: -16px 0; }
|
||||
.ui-icon-carat-1-e { background-position: -32px 0; }
|
||||
.ui-icon-carat-1-se { background-position: -48px 0; }
|
||||
.ui-icon-carat-1-s { background-position: -64px 0; }
|
||||
.ui-icon-carat-1-sw { background-position: -80px 0; }
|
||||
.ui-icon-carat-1-w { background-position: -96px 0; }
|
||||
.ui-icon-carat-1-nw { background-position: -112px 0; }
|
||||
.ui-icon-carat-2-n-s { background-position: -128px 0; }
|
||||
.ui-icon-carat-2-e-w { background-position: -144px 0; }
|
||||
.ui-icon-triangle-1-n { background-position: 0 -16px; }
|
||||
.ui-icon-triangle-1-ne { background-position: -16px -16px; }
|
||||
.ui-icon-triangle-1-e { background-position: -32px -16px; }
|
||||
.ui-icon-triangle-1-se { background-position: -48px -16px; }
|
||||
.ui-icon-triangle-1-s { background-position: -64px -16px; }
|
||||
.ui-icon-triangle-1-sw { background-position: -80px -16px; }
|
||||
.ui-icon-triangle-1-w { background-position: -96px -16px; }
|
||||
.ui-icon-triangle-1-nw { background-position: -112px -16px; }
|
||||
.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
|
||||
.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
|
||||
.ui-icon-arrow-1-n { background-position: 0 -32px; }
|
||||
.ui-icon-arrow-1-ne { background-position: -16px -32px; }
|
||||
.ui-icon-arrow-1-e { background-position: -32px -32px; }
|
||||
.ui-icon-arrow-1-se { background-position: -48px -32px; }
|
||||
.ui-icon-arrow-1-s { background-position: -64px -32px; }
|
||||
.ui-icon-arrow-1-sw { background-position: -80px -32px; }
|
||||
.ui-icon-arrow-1-w { background-position: -96px -32px; }
|
||||
.ui-icon-arrow-1-nw { background-position: -112px -32px; }
|
||||
.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
|
||||
.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
|
||||
.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
|
||||
.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
|
||||
.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
|
||||
.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
|
||||
.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
|
||||
.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
|
||||
.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
|
||||
.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
|
||||
.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
|
||||
.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
|
||||
.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
|
||||
.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
|
||||
.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
|
||||
.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
|
||||
.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
|
||||
.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
|
||||
.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
|
||||
.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
|
||||
.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
|
||||
.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
|
||||
.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
|
||||
.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
|
||||
.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
|
||||
.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
|
||||
.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
|
||||
.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
|
||||
.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
|
||||
.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
|
||||
.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
|
||||
.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
|
||||
.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
|
||||
.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
|
||||
.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
|
||||
.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
|
||||
.ui-icon-arrow-4 { background-position: 0 -80px; }
|
||||
.ui-icon-arrow-4-diag { background-position: -16px -80px; }
|
||||
.ui-icon-extlink { background-position: -32px -80px; }
|
||||
.ui-icon-newwin { background-position: -48px -80px; }
|
||||
.ui-icon-refresh { background-position: -64px -80px; }
|
||||
.ui-icon-shuffle { background-position: -80px -80px; }
|
||||
.ui-icon-transfer-e-w { background-position: -96px -80px; }
|
||||
.ui-icon-transferthick-e-w { background-position: -112px -80px; }
|
||||
.ui-icon-folder-collapsed { background-position: 0 -96px; }
|
||||
.ui-icon-folder-open { background-position: -16px -96px; }
|
||||
.ui-icon-document { background-position: -32px -96px; }
|
||||
.ui-icon-document-b { background-position: -48px -96px; }
|
||||
.ui-icon-note { background-position: -64px -96px; }
|
||||
.ui-icon-mail-closed { background-position: -80px -96px; }
|
||||
.ui-icon-mail-open { background-position: -96px -96px; }
|
||||
.ui-icon-suitcase { background-position: -112px -96px; }
|
||||
.ui-icon-comment { background-position: -128px -96px; }
|
||||
.ui-icon-person { background-position: -144px -96px; }
|
||||
.ui-icon-print { background-position: -160px -96px; }
|
||||
.ui-icon-trash { background-position: -176px -96px; }
|
||||
.ui-icon-locked { background-position: -192px -96px; }
|
||||
.ui-icon-unlocked { background-position: -208px -96px; }
|
||||
.ui-icon-bookmark { background-position: -224px -96px; }
|
||||
.ui-icon-tag { background-position: -240px -96px; }
|
||||
.ui-icon-home { background-position: 0 -112px; }
|
||||
.ui-icon-flag { background-position: -16px -112px; }
|
||||
.ui-icon-calendar { background-position: -32px -112px; }
|
||||
.ui-icon-cart { background-position: -48px -112px; }
|
||||
.ui-icon-pencil { background-position: -64px -112px; }
|
||||
.ui-icon-clock { background-position: -80px -112px; }
|
||||
.ui-icon-disk { background-position: -96px -112px; }
|
||||
.ui-icon-calculator { background-position: -112px -112px; }
|
||||
.ui-icon-zoomin { background-position: -128px -112px; }
|
||||
.ui-icon-zoomout { background-position: -144px -112px; }
|
||||
.ui-icon-search { background-position: -160px -112px; }
|
||||
.ui-icon-wrench { background-position: -176px -112px; }
|
||||
.ui-icon-gear { background-position: -192px -112px; }
|
||||
.ui-icon-heart { background-position: -208px -112px; }
|
||||
.ui-icon-star { background-position: -224px -112px; }
|
||||
.ui-icon-link { background-position: -240px -112px; }
|
||||
.ui-icon-cancel { background-position: 0 -128px; }
|
||||
.ui-icon-plus { background-position: -16px -128px; }
|
||||
.ui-icon-plusthick { background-position: -32px -128px; }
|
||||
.ui-icon-minus { background-position: -48px -128px; }
|
||||
.ui-icon-minusthick { background-position: -64px -128px; }
|
||||
.ui-icon-close { background-position: -80px -128px; }
|
||||
.ui-icon-closethick { background-position: -96px -128px; }
|
||||
.ui-icon-key { background-position: -112px -128px; }
|
||||
.ui-icon-lightbulb { background-position: -128px -128px; }
|
||||
.ui-icon-scissors { background-position: -144px -128px; }
|
||||
.ui-icon-clipboard { background-position: -160px -128px; }
|
||||
.ui-icon-copy { background-position: -176px -128px; }
|
||||
.ui-icon-contact { background-position: -192px -128px; }
|
||||
.ui-icon-image { background-position: -208px -128px; }
|
||||
.ui-icon-video { background-position: -224px -128px; }
|
||||
.ui-icon-script { background-position: -240px -128px; }
|
||||
.ui-icon-alert { background-position: 0 -144px; }
|
||||
.ui-icon-info { background-position: -16px -144px; }
|
||||
.ui-icon-notice { background-position: -32px -144px; }
|
||||
.ui-icon-help { background-position: -48px -144px; }
|
||||
.ui-icon-check { background-position: -64px -144px; }
|
||||
.ui-icon-bullet { background-position: -80px -144px; }
|
||||
.ui-icon-radio-off { background-position: -96px -144px; }
|
||||
.ui-icon-radio-on { background-position: -112px -144px; }
|
||||
.ui-icon-pin-w { background-position: -128px -144px; }
|
||||
.ui-icon-pin-s { background-position: -144px -144px; }
|
||||
.ui-icon-play { background-position: 0 -160px; }
|
||||
.ui-icon-pause { background-position: -16px -160px; }
|
||||
.ui-icon-seek-next { background-position: -32px -160px; }
|
||||
.ui-icon-seek-prev { background-position: -48px -160px; }
|
||||
.ui-icon-seek-end { background-position: -64px -160px; }
|
||||
.ui-icon-seek-start { background-position: -80px -160px; }
|
||||
/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
|
||||
.ui-icon-seek-first { background-position: -80px -160px; }
|
||||
.ui-icon-stop { background-position: -96px -160px; }
|
||||
.ui-icon-eject { background-position: -112px -160px; }
|
||||
.ui-icon-volume-off { background-position: -128px -160px; }
|
||||
.ui-icon-volume-on { background-position: -144px -160px; }
|
||||
.ui-icon-power { background-position: 0 -176px; }
|
||||
.ui-icon-signal-diag { background-position: -16px -176px; }
|
||||
.ui-icon-signal { background-position: -32px -176px; }
|
||||
.ui-icon-battery-0 { background-position: -48px -176px; }
|
||||
.ui-icon-battery-1 { background-position: -64px -176px; }
|
||||
.ui-icon-battery-2 { background-position: -80px -176px; }
|
||||
.ui-icon-battery-3 { background-position: -96px -176px; }
|
||||
.ui-icon-circle-plus { background-position: 0 -192px; }
|
||||
.ui-icon-circle-minus { background-position: -16px -192px; }
|
||||
.ui-icon-circle-close { background-position: -32px -192px; }
|
||||
.ui-icon-circle-triangle-e { background-position: -48px -192px; }
|
||||
.ui-icon-circle-triangle-s { background-position: -64px -192px; }
|
||||
.ui-icon-circle-triangle-w { background-position: -80px -192px; }
|
||||
.ui-icon-circle-triangle-n { background-position: -96px -192px; }
|
||||
.ui-icon-circle-arrow-e { background-position: -112px -192px; }
|
||||
.ui-icon-circle-arrow-s { background-position: -128px -192px; }
|
||||
.ui-icon-circle-arrow-w { background-position: -144px -192px; }
|
||||
.ui-icon-circle-arrow-n { background-position: -160px -192px; }
|
||||
.ui-icon-circle-zoomin { background-position: -176px -192px; }
|
||||
.ui-icon-circle-zoomout { background-position: -192px -192px; }
|
||||
.ui-icon-circle-check { background-position: -208px -192px; }
|
||||
.ui-icon-circlesmall-plus { background-position: 0 -208px; }
|
||||
.ui-icon-circlesmall-minus { background-position: -16px -208px; }
|
||||
.ui-icon-circlesmall-close { background-position: -32px -208px; }
|
||||
.ui-icon-squaresmall-plus { background-position: -48px -208px; }
|
||||
.ui-icon-squaresmall-minus { background-position: -64px -208px; }
|
||||
.ui-icon-squaresmall-close { background-position: -80px -208px; }
|
||||
.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
|
||||
.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
|
||||
.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
|
||||
.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
|
||||
.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
|
||||
.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
|
||||
|
||||
|
||||
/* Misc visuals
|
||||
----------------------------------*/
|
||||
|
||||
/* Corner radius */
|
||||
.ui-corner-tl { -moz-border-radius-topleft: 6px; -webkit-border-top-left-radius: 6px; border-top-left-radius: 6px; }
|
||||
.ui-corner-tr { -moz-border-radius-topright: 6px; -webkit-border-top-right-radius: 6px; border-top-right-radius: 6px; }
|
||||
.ui-corner-bl { -moz-border-radius-bottomleft: 6px; -webkit-border-bottom-left-radius: 6px; border-bottom-left-radius: 6px; }
|
||||
.ui-corner-br { -moz-border-radius-bottomright: 6px; -webkit-border-bottom-right-radius: 6px; border-bottom-right-radius: 6px; }
|
||||
.ui-corner-top { -moz-border-radius-topleft: 6px; -webkit-border-top-left-radius: 6px; border-top-left-radius: 6px; -moz-border-radius-topright: 6px; -webkit-border-top-right-radius: 6px; border-top-right-radius: 6px; }
|
||||
.ui-corner-bottom { -moz-border-radius-bottomleft: 6px; -webkit-border-bottom-left-radius: 6px; border-bottom-left-radius: 6px; -moz-border-radius-bottomright: 6px; -webkit-border-bottom-right-radius: 6px; border-bottom-right-radius: 6px; }
|
||||
.ui-corner-right { -moz-border-radius-topright: 6px; -webkit-border-top-right-radius: 6px; border-top-right-radius: 6px; -moz-border-radius-bottomright: 6px; -webkit-border-bottom-right-radius: 6px; border-bottom-right-radius: 6px; }
|
||||
.ui-corner-left { -moz-border-radius-topleft: 6px; -webkit-border-top-left-radius: 6px; border-top-left-radius: 6px; -moz-border-radius-bottomleft: 6px; -webkit-border-bottom-left-radius: 6px; border-bottom-left-radius: 6px; }
|
||||
.ui-corner-all { -moz-border-radius: 6px; -webkit-border-radius: 6px; border-radius: 6px; }
|
||||
|
||||
/* 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-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
|
||||
*
|
||||
* 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/Accordion#theming
|
||||
*/
|
||||
/* IE/Win - Fix animation bug - #4615 */
|
||||
.ui-accordion { width: 100%; }
|
||||
.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; }
|
||||
.ui-accordion .ui-accordion-li-fix { display: inline; }
|
||||
.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; }
|
||||
.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; }
|
||||
.ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; }
|
||||
.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }
|
||||
.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; }
|
||||
.ui-accordion .ui-accordion-content-active { display: block; }/*
|
||||
* jQuery UI Button @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/Button#theming
|
||||
*/
|
||||
.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */
|
||||
.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */
|
||||
button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */
|
||||
.ui-button-icons-only { width: 3.4em; }
|
||||
button.ui-button-icons-only { width: 3.7em; }
|
||||
|
||||
/*button text element */
|
||||
.ui-button .ui-button-text { display: block; line-height: 1.4; }
|
||||
.ui-button-text-only .ui-button-text { padding: .4em 1em; }
|
||||
.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; }
|
||||
.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; }
|
||||
.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; }
|
||||
.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; }
|
||||
/* no icon support for input elements, provide padding by default */
|
||||
input.ui-button { padding: .4em 1em; }
|
||||
|
||||
/*button icon element(s) */
|
||||
.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; }
|
||||
.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; }
|
||||
.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; }
|
||||
.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
|
||||
.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
|
||||
|
||||
/*button sets*/
|
||||
.ui-buttonset { margin-right: 7px; }
|
||||
.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; }
|
||||
|
||||
/* workarounds */
|
||||
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; }
|
426
resources/content_server/jquery_ui/js/jquery-ui-1.8.5.custom.min.js
vendored
Normal file
@ -0,0 +1,426 @@
|
||||
/*!
|
||||
* jQuery UI 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
|
||||
*/
|
||||
(function(c,j){function k(a){return!c(a).parents().andSelf().filter(function(){return c.curCSS(this,"visibility")==="hidden"||c.expr.filters.hidden(this)}).length}c.ui=c.ui||{};if(!c.ui.version){c.extend(c.ui,{version:"1.8.5",keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,
|
||||
NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}});c.fn.extend({_focus:c.fn.focus,focus:function(a,b){return typeof a==="number"?this.each(function(){var d=this;setTimeout(function(){c(d).focus();b&&b.call(d)},a)}):this._focus.apply(this,arguments)},scrollParent:function(){var a;a=c.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(c.curCSS(this,
|
||||
"position",1))&&/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0);return/fixed/.test(this.css("position"))||!a.length?c(document):a},zIndex:function(a){if(a!==j)return this.css("zIndex",a);if(this.length){a=c(this[0]);for(var b;a.length&&a[0]!==document;){b=a.css("position");
|
||||
if(b==="absolute"||b==="relative"||b==="fixed"){b=parseInt(a.css("zIndex"));if(!isNaN(b)&&b!=0)return b}a=a.parent()}}return 0},disableSelection:function(){return this.bind("mousedown.ui-disableSelection selectstart.ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}});c.each(["Width","Height"],function(a,b){function d(f,g,l,m){c.each(e,function(){g-=parseFloat(c.curCSS(f,"padding"+this,true))||0;if(l)g-=parseFloat(c.curCSS(f,
|
||||
"border"+this+"Width",true))||0;if(m)g-=parseFloat(c.curCSS(f,"margin"+this,true))||0});return g}var e=b==="Width"?["Left","Right"]:["Top","Bottom"],h=b.toLowerCase(),i={innerWidth:c.fn.innerWidth,innerHeight:c.fn.innerHeight,outerWidth:c.fn.outerWidth,outerHeight:c.fn.outerHeight};c.fn["inner"+b]=function(f){if(f===j)return i["inner"+b].call(this);return this.each(function(){c.style(this,h,d(this,f)+"px")})};c.fn["outer"+b]=function(f,g){if(typeof f!=="number")return i["outer"+b].call(this,f);return this.each(function(){c.style(this,
|
||||
h,d(this,f,true,g)+"px")})}});c.extend(c.expr[":"],{data:function(a,b,d){return!!c.data(a,d[3])},focusable:function(a){var b=a.nodeName.toLowerCase(),d=c.attr(a,"tabindex");if("area"===b){b=a.parentNode;d=b.name;if(!a.href||!d||b.nodeName.toLowerCase()!=="map")return false;a=c("img[usemap=#"+d+"]")[0];return!!a&&k(a)}return(/input|select|textarea|button|object/.test(b)?!a.disabled:"a"==b?a.href||!isNaN(d):!isNaN(d))&&k(a)},tabbable:function(a){var b=c.attr(a,"tabindex");return(isNaN(b)||b>=0)&&c(a).is(":focusable")}});
|
||||
c(function(){var a=document.createElement("div"),b=document.body;c.extend(a.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0});c.support.minHeight=b.appendChild(a).offsetHeight===100;b.removeChild(a).style.display="none"});c.extend(c.ui,{plugin:{add:function(a,b,d){a=c.ui[a].prototype;for(var e in d){a.plugins[e]=a.plugins[e]||[];a.plugins[e].push([b,d[e]])}},call:function(a,b,d){if((b=a.plugins[b])&&a.element[0].parentNode)for(var e=0;e<b.length;e++)a.options[b[e][0]]&&b[e][1].apply(a.element,
|
||||
d)}},contains:function(a,b){return document.compareDocumentPosition?a.compareDocumentPosition(b)&16:a!==b&&a.contains(b)},hasScroll:function(a,b){if(c(a).css("overflow")==="hidden")return false;b=b&&b==="left"?"scrollLeft":"scrollTop";var d=false;if(a[b]>0)return true;a[b]=1;d=a[b]>0;a[b]=0;return d},isOverAxis:function(a,b,d){return a>b&&a<b+d},isOver:function(a,b,d,e,h,i){return c.ui.isOverAxis(a,d,h)&&c.ui.isOverAxis(b,e,i)}})}})(jQuery);
|
||||
;/*!
|
||||
* jQuery UI Widget 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/Widget
|
||||
*/
|
||||
(function(b,j){if(b.cleanData){var k=b.cleanData;b.cleanData=function(a){for(var c=0,d;(d=a[c])!=null;c++)b(d).triggerHandler("remove");k(a)}}else{var l=b.fn.remove;b.fn.remove=function(a,c){return this.each(function(){if(!c)if(!a||b.filter(a,[this]).length)b("*",this).add([this]).each(function(){b(this).triggerHandler("remove")});return l.call(b(this),a,c)})}}b.widget=function(a,c,d){var e=a.split(".")[0],f;a=a.split(".")[1];f=e+"-"+a;if(!d){d=c;c=b.Widget}b.expr[":"][f]=function(h){return!!b.data(h,
|
||||
a)};b[e]=b[e]||{};b[e][a]=function(h,g){arguments.length&&this._createWidget(h,g)};c=new c;c.options=b.extend(true,{},c.options);b[e][a].prototype=b.extend(true,c,{namespace:e,widgetName:a,widgetEventPrefix:b[e][a].prototype.widgetEventPrefix||a,widgetBaseClass:f},d);b.widget.bridge(a,b[e][a])};b.widget.bridge=function(a,c){b.fn[a]=function(d){var e=typeof d==="string",f=Array.prototype.slice.call(arguments,1),h=this;d=!e&&f.length?b.extend.apply(null,[true,d].concat(f)):d;if(e&&d.substring(0,1)===
|
||||
"_")return h;e?this.each(function(){var g=b.data(this,a);if(!g)throw"cannot call methods on "+a+" prior to initialization; attempted to call method '"+d+"'";if(!b.isFunction(g[d]))throw"no such method '"+d+"' for "+a+" widget instance";var i=g[d].apply(g,f);if(i!==g&&i!==j){h=i;return false}}):this.each(function(){var g=b.data(this,a);g?g.option(d||{})._init():b.data(this,a,new c(d,this))});return h}};b.Widget=function(a,c){arguments.length&&this._createWidget(a,c)};b.Widget.prototype={widgetName:"widget",
|
||||
widgetEventPrefix:"",options:{disabled:false},_createWidget:function(a,c){b.data(c,this.widgetName,this);this.element=b(c);this.options=b.extend(true,{},this.options,b.metadata&&b.metadata.get(c)[this.widgetName],a);var d=this;this.element.bind("remove."+this.widgetName,function(){d.destroy()});this._create();this._init()},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName);this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+
|
||||
"-disabled ui-state-disabled")},widget:function(){return this.element},option:function(a,c){var d=a,e=this;if(arguments.length===0)return b.extend({},e.options);if(typeof a==="string"){if(c===j)return this.options[a];d={};d[a]=c}b.each(d,function(f,h){e._setOption(f,h)});return e},_setOption:function(a,c){this.options[a]=c;if(a==="disabled")this.widget()[c?"addClass":"removeClass"](this.widgetBaseClass+"-disabled ui-state-disabled").attr("aria-disabled",c);return this},enable:function(){return this._setOption("disabled",
|
||||
false)},disable:function(){return this._setOption("disabled",true)},_trigger:function(a,c,d){var e=this.options[a];c=b.Event(c);c.type=(a===this.widgetEventPrefix?a:this.widgetEventPrefix+a).toLowerCase();d=d||{};if(c.originalEvent){a=b.event.props.length;for(var f;a;){f=b.event.props[--a];c[f]=c.originalEvent[f]}}this.element.trigger(c,d);return!(b.isFunction(e)&&e.call(this.element[0],c,d)===false||c.isDefaultPrevented())}}})(jQuery);
|
||||
;/*!
|
||||
* jQuery UI Mouse 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/Mouse
|
||||
*
|
||||
* Depends:
|
||||
* jquery.ui.widget.js
|
||||
*/
|
||||
(function(c){c.widget("ui.mouse",{options:{cancel:":input,option",distance:1,delay:0},_mouseInit:function(){var a=this;this.element.bind("mousedown."+this.widgetName,function(b){return a._mouseDown(b)}).bind("click."+this.widgetName,function(b){if(a._preventClickEvent){a._preventClickEvent=false;b.stopImmediatePropagation();return false}});this.started=false},_mouseDestroy:function(){this.element.unbind("."+this.widgetName)},_mouseDown:function(a){a.originalEvent=a.originalEvent||{};if(!a.originalEvent.mouseHandled){this._mouseStarted&&
|
||||
this._mouseUp(a);this._mouseDownEvent=a;var b=this,e=a.which==1,f=typeof this.options.cancel=="string"?c(a.target).parents().add(a.target).filter(this.options.cancel).length:false;if(!e||f||!this._mouseCapture(a))return true;this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet)this._mouseDelayTimer=setTimeout(function(){b.mouseDelayMet=true},this.options.delay);if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a)){this._mouseStarted=this._mouseStart(a)!==false;if(!this._mouseStarted){a.preventDefault();
|
||||
return true}}this._mouseMoveDelegate=function(d){return b._mouseMove(d)};this._mouseUpDelegate=function(d){return b._mouseUp(d)};c(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);c.browser.safari||a.preventDefault();return a.originalEvent.mouseHandled=true}},_mouseMove:function(a){if(c.browser.msie&&!a.button)return this._mouseUp(a);if(this._mouseStarted){this._mouseDrag(a);return a.preventDefault()}if(this._mouseDistanceMet(a)&&
|
||||
this._mouseDelayMet(a))(this._mouseStarted=this._mouseStart(this._mouseDownEvent,a)!==false)?this._mouseDrag(a):this._mouseUp(a);return!this._mouseStarted},_mouseUp:function(a){c(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;this._preventClickEvent=a.target==this._mouseDownEvent.target;this._mouseStop(a)}return false},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-
|
||||
a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return true}})})(jQuery);
|
||||
;/*
|
||||
* jQuery UI Position 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/Position
|
||||
*/
|
||||
(function(c){c.ui=c.ui||{};var n=/left|center|right/,o=/top|center|bottom/,t=c.fn.position,u=c.fn.offset;c.fn.position=function(b){if(!b||!b.of)return t.apply(this,arguments);b=c.extend({},b);var a=c(b.of),d=a[0],g=(b.collision||"flip").split(" "),e=b.offset?b.offset.split(" "):[0,0],h,k,j;if(d.nodeType===9){h=a.width();k=a.height();j={top:0,left:0}}else if(d.scrollTo&&d.document){h=a.width();k=a.height();j={top:a.scrollTop(),left:a.scrollLeft()}}else if(d.preventDefault){b.at="left top";h=k=0;j=
|
||||
{top:b.of.pageY,left:b.of.pageX}}else{h=a.outerWidth();k=a.outerHeight();j=a.offset()}c.each(["my","at"],function(){var f=(b[this]||"").split(" ");if(f.length===1)f=n.test(f[0])?f.concat(["center"]):o.test(f[0])?["center"].concat(f):["center","center"];f[0]=n.test(f[0])?f[0]:"center";f[1]=o.test(f[1])?f[1]:"center";b[this]=f});if(g.length===1)g[1]=g[0];e[0]=parseInt(e[0],10)||0;if(e.length===1)e[1]=e[0];e[1]=parseInt(e[1],10)||0;if(b.at[0]==="right")j.left+=h;else if(b.at[0]==="center")j.left+=h/
|
||||
2;if(b.at[1]==="bottom")j.top+=k;else if(b.at[1]==="center")j.top+=k/2;j.left+=e[0];j.top+=e[1];return this.each(function(){var f=c(this),l=f.outerWidth(),m=f.outerHeight(),p=parseInt(c.curCSS(this,"marginLeft",true))||0,q=parseInt(c.curCSS(this,"marginTop",true))||0,v=l+p+parseInt(c.curCSS(this,"marginRight",true))||0,w=m+q+parseInt(c.curCSS(this,"marginBottom",true))||0,i=c.extend({},j),r;if(b.my[0]==="right")i.left-=l;else if(b.my[0]==="center")i.left-=l/2;if(b.my[1]==="bottom")i.top-=m;else if(b.my[1]===
|
||||
"center")i.top-=m/2;i.left=parseInt(i.left);i.top=parseInt(i.top);r={left:i.left-p,top:i.top-q};c.each(["left","top"],function(s,x){c.ui.position[g[s]]&&c.ui.position[g[s]][x](i,{targetWidth:h,targetHeight:k,elemWidth:l,elemHeight:m,collisionPosition:r,collisionWidth:v,collisionHeight:w,offset:e,my:b.my,at:b.at})});c.fn.bgiframe&&f.bgiframe();f.offset(c.extend(i,{using:b.using}))})};c.ui.position={fit:{left:function(b,a){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();
|
||||
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=
|
||||
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
|
||||
*
|
||||
* 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/Accordion
|
||||
*
|
||||
* Depends:
|
||||
* jquery.ui.core.js
|
||||
* jquery.ui.widget.js
|
||||
*/
|
||||
(function(c){c.widget("ui.accordion",{options:{active:0,animated:"slide",autoHeight:true,clearStyle:false,collapsible:false,event:"click",fillSpace:false,header:"> li > :first-child,> :not(li):even",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:false,navigationFilter:function(){return this.href.toLowerCase()===location.href.toLowerCase()}},_create:function(){var a=this,b=a.options;a.running=0;a.element.addClass("ui-accordion ui-widget ui-helper-reset").children("li").addClass("ui-accordion-li-fix");
|
||||
a.headers=a.element.find(b.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all").bind("mouseenter.accordion",function(){b.disabled||c(this).addClass("ui-state-hover")}).bind("mouseleave.accordion",function(){b.disabled||c(this).removeClass("ui-state-hover")}).bind("focus.accordion",function(){b.disabled||c(this).addClass("ui-state-focus")}).bind("blur.accordion",function(){b.disabled||c(this).removeClass("ui-state-focus")});a.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom");
|
||||
if(b.navigation){var d=a.element.find("a").filter(b.navigationFilter).eq(0);if(d.length){var f=d.closest(".ui-accordion-header");a.active=f.length?f:d.closest(".ui-accordion-content").prev()}}a.active=a._findActive(a.active||b.active).addClass("ui-state-default ui-state-active").toggleClass("ui-corner-all ui-corner-top");a.active.next().addClass("ui-accordion-content-active");a._createIcons();a.resize();a.element.attr("role","tablist");a.headers.attr("role","tab").bind("keydown.accordion",function(g){return a._keydown(g)}).next().attr("role",
|
||||
"tabpanel");a.headers.not(a.active||"").attr({"aria-expanded":"false",tabIndex:-1}).next().hide();a.active.length?a.active.attr({"aria-expanded":"true",tabIndex:0}):a.headers.eq(0).attr("tabIndex",0);c.browser.safari||a.headers.find("a").attr("tabIndex",-1);b.event&&a.headers.bind(b.event.split(" ").join(".accordion ")+".accordion",function(g){a._clickHandler.call(a,g,this);g.preventDefault()})},_createIcons:function(){var a=this.options;if(a.icons){c("<span></span>").addClass("ui-icon "+a.icons.header).prependTo(this.headers);
|
||||
this.active.children(".ui-icon").toggleClass(a.icons.header).toggleClass(a.icons.headerSelected);this.element.addClass("ui-accordion-icons")}},_destroyIcons:function(){this.headers.children(".ui-icon").remove();this.element.removeClass("ui-accordion-icons")},destroy:function(){var a=this.options;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role");this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("tabIndex");
|
||||
this.headers.find("a").removeAttr("tabIndex");this._destroyIcons();var b=this.headers.next().css("display","").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled");if(a.autoHeight||a.fillHeight)b.css("height","");return c.Widget.prototype.destroy.call(this)},_setOption:function(a,b){c.Widget.prototype._setOption.apply(this,arguments);a=="active"&&this.activate(b);if(a=="icons"){this._destroyIcons();
|
||||
b&&this._createIcons()}if(a=="disabled")this.headers.add(this.headers.next())[b?"addClass":"removeClass"]("ui-accordion-disabled ui-state-disabled")},_keydown:function(a){if(!(this.options.disabled||a.altKey||a.ctrlKey)){var b=c.ui.keyCode,d=this.headers.length,f=this.headers.index(a.target),g=false;switch(a.keyCode){case b.RIGHT:case b.DOWN:g=this.headers[(f+1)%d];break;case b.LEFT:case b.UP:g=this.headers[(f-1+d)%d];break;case b.SPACE:case b.ENTER:this._clickHandler({target:a.target},a.target);
|
||||
a.preventDefault()}if(g){c(a.target).attr("tabIndex",-1);c(g).attr("tabIndex",0);g.focus();return false}return true}},resize:function(){var a=this.options,b;if(a.fillSpace){if(c.browser.msie){var d=this.element.parent().css("overflow");this.element.parent().css("overflow","hidden")}b=this.element.parent().height();c.browser.msie&&this.element.parent().css("overflow",d);this.headers.each(function(){b-=c(this).outerHeight(true)});this.headers.next().each(function(){c(this).height(Math.max(0,b-c(this).innerHeight()+
|
||||
c(this).height()))}).css("overflow","auto")}else if(a.autoHeight){b=0;this.headers.next().each(function(){b=Math.max(b,c(this).height("").height())}).height(b)}return this},activate:function(a){this.options.active=a;a=this._findActive(a)[0];this._clickHandler({target:a},a);return this},_findActive:function(a){return a?typeof a==="number"?this.headers.filter(":eq("+a+")"):this.headers.not(this.headers.not(a)):a===false?c([]):this.headers.filter(":eq(0)")},_clickHandler:function(a,b){var d=this.options;
|
||||
if(!d.disabled)if(a.target){a=c(a.currentTarget||b);b=a[0]===this.active[0];d.active=d.collapsible&&b?false:this.headers.index(a);if(!(this.running||!d.collapsible&&b)){this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header);if(!b){a.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top").children(".ui-icon").removeClass(d.icons.header).addClass(d.icons.headerSelected);
|
||||
a.next().addClass("ui-accordion-content-active")}h=a.next();f=this.active.next();g={options:d,newHeader:b&&d.collapsible?c([]):a,oldHeader:this.active,newContent:b&&d.collapsible?c([]):h,oldContent:f};d=this.headers.index(this.active[0])>this.headers.index(a[0]);this.active=b?c([]):a;this._toggle(h,f,g,b,d)}}else if(d.collapsible){this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header);
|
||||
this.active.next().addClass("ui-accordion-content-active");var f=this.active.next(),g={options:d,newHeader:c([]),oldHeader:d.active,newContent:c([]),oldContent:f},h=this.active=c([]);this._toggle(h,f,g)}},_toggle:function(a,b,d,f,g){var h=this,e=h.options;h.toShow=a;h.toHide=b;h.data=d;var j=function(){if(h)return h._completed.apply(h,arguments)};h._trigger("changestart",null,h.data);h.running=b.size()===0?a.size():b.size();if(e.animated){d={};d=e.collapsible&&f?{toShow:c([]),toHide:b,complete:j,
|
||||
down:g,autoHeight:e.autoHeight||e.fillSpace}:{toShow:a,toHide:b,complete:j,down:g,autoHeight:e.autoHeight||e.fillSpace};if(!e.proxied)e.proxied=e.animated;if(!e.proxiedDuration)e.proxiedDuration=e.duration;e.animated=c.isFunction(e.proxied)?e.proxied(d):e.proxied;e.duration=c.isFunction(e.proxiedDuration)?e.proxiedDuration(d):e.proxiedDuration;f=c.ui.accordion.animations;var i=e.duration,k=e.animated;if(k&&!f[k]&&!c.easing[k])k="slide";f[k]||(f[k]=function(l){this.slide(l,{easing:k,duration:i||700})});
|
||||
f[k](d)}else{if(e.collapsible&&f)a.toggle();else{b.hide();a.show()}j(true)}b.prev().attr({"aria-expanded":"false",tabIndex:-1}).blur();a.prev().attr({"aria-expanded":"true",tabIndex:0}).focus()},_completed:function(a){this.running=a?0:--this.running;if(!this.running){this.options.clearStyle&&this.toShow.add(this.toHide).css({height:"",overflow:""});this.toHide.removeClass("ui-accordion-content-active");this._trigger("change",null,this.data)}}});c.extend(c.ui.accordion,{version:"1.8.5",animations:{slide:function(a,
|
||||
b){a=c.extend({easing:"swing",duration:300},a,b);if(a.toHide.size())if(a.toShow.size()){var d=a.toShow.css("overflow"),f=0,g={},h={},e;b=a.toShow;e=b[0].style.width;b.width(parseInt(b.parent().width(),10)-parseInt(b.css("paddingLeft"),10)-parseInt(b.css("paddingRight"),10)-(parseInt(b.css("borderLeftWidth"),10)||0)-(parseInt(b.css("borderRightWidth"),10)||0));c.each(["height","paddingTop","paddingBottom"],function(j,i){h[i]="hide";j=(""+c.css(a.toShow[0],i)).match(/^([\d+-.]+)(.*)$/);g[i]={value:j[1],
|
||||
unit:j[2]||"px"}});a.toShow.css({height:0,overflow:"hidden"}).show();a.toHide.filter(":hidden").each(a.complete).end().filter(":visible").animate(h,{step:function(j,i){if(i.prop=="height")f=i.end-i.start===0?0:(i.now-i.start)/(i.end-i.start);a.toShow[0].style[i.prop]=f*g[i.prop].value+g[i.prop].unit},duration:a.duration,easing:a.easing,complete:function(){a.autoHeight||a.toShow.css("height","");a.toShow.css({width:e,overflow:d});a.complete()}})}else a.toHide.animate({height:"hide",paddingTop:"hide",
|
||||
paddingBottom:"hide"},a);else a.toShow.animate({height:"show",paddingTop:"show",paddingBottom:"show"},a)},bounceslide:function(a){this.slide(a,{easing:a.down?"easeOutBounce":"swing",duration:a.down?1E3:200})}}})})(jQuery);
|
||||
;/*
|
||||
* jQuery UI Button 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/Button
|
||||
*
|
||||
* Depends:
|
||||
* jquery.ui.core.js
|
||||
* jquery.ui.widget.js
|
||||
*/
|
||||
(function(a){var g,i=function(b){a(":ui-button",b.target.form).each(function(){var c=a(this).data("button");setTimeout(function(){c.refresh()},1)})},h=function(b){var c=b.name,d=b.form,e=a([]);if(c)e=d?a(d).find("[name='"+c+"']"):a("[name='"+c+"']",b.ownerDocument).filter(function(){return!this.form});return e};a.widget("ui.button",{options:{disabled:null,text:true,label:null,icons:{primary:null,secondary:null}},_create:function(){this.element.closest("form").unbind("reset.button").bind("reset.button",
|
||||
i);if(typeof this.options.disabled!=="boolean")this.options.disabled=this.element.attr("disabled");this._determineButtonType();this.hasTitle=!!this.buttonElement.attr("title");var b=this,c=this.options,d=this.type==="checkbox"||this.type==="radio",e="ui-state-hover"+(!d?" ui-state-active":"");if(c.label===null)c.label=this.buttonElement.html();if(this.element.is(":disabled"))c.disabled=true;this.buttonElement.addClass("ui-button ui-widget ui-state-default ui-corner-all").attr("role","button").bind("mouseenter.button",
|
||||
function(){if(!c.disabled){a(this).addClass("ui-state-hover");this===g&&a(this).addClass("ui-state-active")}}).bind("mouseleave.button",function(){c.disabled||a(this).removeClass(e)}).bind("focus.button",function(){a(this).addClass("ui-state-focus")}).bind("blur.button",function(){a(this).removeClass("ui-state-focus")});d&&this.element.bind("change.button",function(){b.refresh()});if(this.type==="checkbox")this.buttonElement.bind("click.button",function(){if(c.disabled)return false;a(this).toggleClass("ui-state-active");
|
||||
b.buttonElement.attr("aria-pressed",b.element[0].checked)});else if(this.type==="radio")this.buttonElement.bind("click.button",function(){if(c.disabled)return false;a(this).addClass("ui-state-active");b.buttonElement.attr("aria-pressed",true);var f=b.element[0];h(f).not(f).map(function(){return a(this).button("widget")[0]}).removeClass("ui-state-active").attr("aria-pressed",false)});else{this.buttonElement.bind("mousedown.button",function(){if(c.disabled)return false;a(this).addClass("ui-state-active");
|
||||
g=this;a(document).one("mouseup",function(){g=null})}).bind("mouseup.button",function(){if(c.disabled)return false;a(this).removeClass("ui-state-active")}).bind("keydown.button",function(f){if(c.disabled)return false;if(f.keyCode==a.ui.keyCode.SPACE||f.keyCode==a.ui.keyCode.ENTER)a(this).addClass("ui-state-active")}).bind("keyup.button",function(){a(this).removeClass("ui-state-active")});this.buttonElement.is("a")&&this.buttonElement.keyup(function(f){f.keyCode===a.ui.keyCode.SPACE&&a(this).click()})}this._setOption("disabled",
|
||||
c.disabled)},_determineButtonType:function(){this.type=this.element.is(":checkbox")?"checkbox":this.element.is(":radio")?"radio":this.element.is("input")?"input":"button";if(this.type==="checkbox"||this.type==="radio"){this.buttonElement=this.element.parents().last().find("label[for="+this.element.attr("id")+"]");this.element.addClass("ui-helper-hidden-accessible");var b=this.element.is(":checked");b&&this.buttonElement.addClass("ui-state-active");this.buttonElement.attr("aria-pressed",b)}else this.buttonElement=
|
||||
this.element},widget:function(){return this.buttonElement},destroy:function(){this.element.removeClass("ui-helper-hidden-accessible");this.buttonElement.removeClass("ui-button ui-widget ui-state-default ui-corner-all ui-state-hover ui-state-active ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only").removeAttr("role").removeAttr("aria-pressed").html(this.buttonElement.find(".ui-button-text").html());this.hasTitle||
|
||||
this.buttonElement.removeAttr("title");a.Widget.prototype.destroy.call(this)},_setOption:function(b,c){a.Widget.prototype._setOption.apply(this,arguments);if(b==="disabled")c?this.element.attr("disabled",true):this.element.removeAttr("disabled");this._resetButton()},refresh:function(){var b=this.element.is(":disabled");b!==this.options.disabled&&this._setOption("disabled",b);if(this.type==="radio")h(this.element[0]).each(function(){a(this).is(":checked")?a(this).button("widget").addClass("ui-state-active").attr("aria-pressed",
|
||||
true):a(this).button("widget").removeClass("ui-state-active").attr("aria-pressed",false)});else if(this.type==="checkbox")this.element.is(":checked")?this.buttonElement.addClass("ui-state-active").attr("aria-pressed",true):this.buttonElement.removeClass("ui-state-active").attr("aria-pressed",false)},_resetButton:function(){if(this.type==="input")this.options.label&&this.element.val(this.options.label);else{var b=this.buttonElement.removeClass("ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only"),
|
||||
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()},
|
||||
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||" ",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||" "));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
|
||||
*
|
||||
* 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/Effects/
|
||||
*/
|
||||
jQuery.effects||function(f,j){function l(c){var a;if(c&&c.constructor==Array&&c.length==3)return c;if(a=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(c))return[parseInt(a[1],10),parseInt(a[2],10),parseInt(a[3],10)];if(a=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(c))return[parseFloat(a[1])*2.55,parseFloat(a[2])*2.55,parseFloat(a[3])*2.55];if(a=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(c))return[parseInt(a[1],
|
||||
16),parseInt(a[2],16),parseInt(a[3],16)];if(a=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(c))return[parseInt(a[1]+a[1],16),parseInt(a[2]+a[2],16),parseInt(a[3]+a[3],16)];if(/rgba\(0, 0, 0, 0\)/.exec(c))return m.transparent;return m[f.trim(c).toLowerCase()]}function r(c,a){var b;do{b=f.curCSS(c,a);if(b!=""&&b!="transparent"||f.nodeName(c,"body"))break;a="backgroundColor"}while(c=c.parentNode);return l(b)}function n(){var c=document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle,
|
||||
a={},b,d;if(c&&c.length&&c[0]&&c[c[0]])for(var e=c.length;e--;){b=c[e];if(typeof c[b]=="string"){d=b.replace(/\-(\w)/g,function(g,h){return h.toUpperCase()});a[d]=c[b]}}else for(b in c)if(typeof c[b]==="string")a[b]=c[b];return a}function o(c){var a,b;for(a in c){b=c[a];if(b==null||f.isFunction(b)||a in s||/scrollbar/.test(a)||!/color/i.test(a)&&isNaN(parseFloat(b)))delete c[a]}return c}function t(c,a){var b={_:0},d;for(d in a)if(c[d]!=a[d])b[d]=a[d];return b}function k(c,a,b,d){if(typeof c=="object"){d=
|
||||
a;b=null;a=c;c=a.effect}if(f.isFunction(a)){d=a;b=null;a={}}if(typeof a=="number"||f.fx.speeds[a]){d=b;b=a;a={}}if(f.isFunction(b)){d=b;b=null}a=a||{};b=b||a.duration;b=f.fx.off?0:typeof b=="number"?b:f.fx.speeds[b]||f.fx.speeds._default;d=d||a.complete;return[c,a,b,d]}f.effects={};f.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor","borderTopColor","color","outlineColor"],function(c,a){f.fx.step[a]=function(b){if(!b.colorInit){b.start=r(b.elem,a);b.end=l(b.end);b.colorInit=
|
||||
true}b.elem.style[a]="rgb("+Math.max(Math.min(parseInt(b.pos*(b.end[0]-b.start[0])+b.start[0],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[1]-b.start[1])+b.start[1],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[2]-b.start[2])+b.start[2],10),255),0)+")"}});var m={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,
|
||||
183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,
|
||||
165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]},p=["add","remove","toggle"],s={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};f.effects.animateClass=function(c,a,b,d){if(f.isFunction(b)){d=b;b=null}return this.each(function(){var e=f(this),g=e.attr("style")||" ",h=o(n.call(this)),q,u=e.attr("className");f.each(p,function(v,
|
||||
i){c[i]&&e[i+"Class"](c[i])});q=o(n.call(this));e.attr("className",u);e.animate(t(h,q),a,b,function(){f.each(p,function(v,i){c[i]&&e[i+"Class"](c[i])});if(typeof e.attr("style")=="object"){e.attr("style").cssText="";e.attr("style").cssText=g}else e.attr("style",g);d&&d.apply(this,arguments)})})};f.fn.extend({_addClass:f.fn.addClass,addClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{add:c},a,b,d]):this._addClass(c)},_removeClass:f.fn.removeClass,removeClass:function(c,a,b,d){return a?
|
||||
f.effects.animateClass.apply(this,[{remove:c},a,b,d]):this._removeClass(c)},_toggleClass:f.fn.toggleClass,toggleClass:function(c,a,b,d,e){return typeof a=="boolean"||a===j?b?f.effects.animateClass.apply(this,[a?{add:c}:{remove:c},b,d,e]):this._toggleClass(c,a):f.effects.animateClass.apply(this,[{toggle:c},a,b,d])},switchClass:function(c,a,b,d,e){return f.effects.animateClass.apply(this,[{add:a,remove:c},b,d,e])}});f.extend(f.effects,{version:"1.8.5",save:function(c,a){for(var b=0;b<a.length;b++)a[b]!==
|
||||
null&&c.data("ec.storage."+a[b],c[0].style[a[b]])},restore:function(c,a){for(var b=0;b<a.length;b++)a[b]!==null&&c.css(a[b],c.data("ec.storage."+a[b]))},setMode:function(c,a){if(a=="toggle")a=c.is(":hidden")?"show":"hide";return a},getBaseline:function(c,a){var b;switch(c[0]){case "top":b=0;break;case "middle":b=0.5;break;case "bottom":b=1;break;default:b=c[0]/a.height}switch(c[1]){case "left":c=0;break;case "center":c=0.5;break;case "right":c=1;break;default:c=c[1]/a.width}return{x:c,y:b}},createWrapper:function(c){if(c.parent().is(".ui-effects-wrapper"))return c.parent();
|
||||
var a={width:c.outerWidth(true),height:c.outerHeight(true),"float":c.css("float")},b=f("<div></div>").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0});c.wrap(b);b=c.parent();if(c.css("position")=="static"){b.css({position:"relative"});c.css({position:"relative"})}else{f.extend(a,{position:c.css("position"),zIndex:c.css("z-index")});f.each(["top","left","bottom","right"],function(d,e){a[e]=c.css(e);if(isNaN(parseInt(a[e],10)))a[e]="auto"});
|
||||
c.css({position:"relative",top:0,left:0})}return b.css(a).show()},removeWrapper:function(c){if(c.parent().is(".ui-effects-wrapper"))return c.parent().replaceWith(c);return c},setTransition:function(c,a,b,d){d=d||{};f.each(a,function(e,g){unit=c.cssUnit(g);if(unit[0]>0)d[g]=unit[0]*b+unit[1]});return d}});f.fn.extend({effect:function(c){var a=k.apply(this,arguments);a={options:a[1],duration:a[2],callback:a[3]};var b=f.effects[c];return b&&!f.fx.off?b.call(this,a):this},_show:f.fn.show,show:function(c){if(!c||
|
||||
typeof c=="number"||f.fx.speeds[c]||!f.effects[c])return this._show.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="show";return this.effect.apply(this,a)}},_hide:f.fn.hide,hide:function(c){if(!c||typeof c=="number"||f.fx.speeds[c]||!f.effects[c])return this._hide.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="hide";return this.effect.apply(this,a)}},__toggle:f.fn.toggle,toggle:function(c){if(!c||typeof c=="number"||f.fx.speeds[c]||!f.effects[c]||typeof c==
|
||||
"boolean"||f.isFunction(c))return this.__toggle.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="toggle";return this.effect.apply(this,a)}},cssUnit:function(c){var a=this.css(c),b=[];f.each(["em","px","%","pt"],function(d,e){if(a.indexOf(e)>0)b=[parseFloat(a),e]});return b}});f.easing.jswing=f.easing.swing;f.extend(f.easing,{def:"easeOutQuad",swing:function(c,a,b,d,e){return f.easing[f.easing.def](c,a,b,d,e)},easeInQuad:function(c,a,b,d,e){return d*(a/=e)*a+b},easeOutQuad:function(c,
|
||||
a,b,d,e){return-d*(a/=e)*(a-2)+b},easeInOutQuad:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a+b;return-d/2*(--a*(a-2)-1)+b},easeInCubic:function(c,a,b,d,e){return d*(a/=e)*a*a+b},easeOutCubic:function(c,a,b,d,e){return d*((a=a/e-1)*a*a+1)+b},easeInOutCubic:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a+b;return d/2*((a-=2)*a*a+2)+b},easeInQuart:function(c,a,b,d,e){return d*(a/=e)*a*a*a+b},easeOutQuart:function(c,a,b,d,e){return-d*((a=a/e-1)*a*a*a-1)+b},easeInOutQuart:function(c,a,b,d,e){if((a/=
|
||||
e/2)<1)return d/2*a*a*a*a+b;return-d/2*((a-=2)*a*a*a-2)+b},easeInQuint:function(c,a,b,d,e){return d*(a/=e)*a*a*a*a+b},easeOutQuint:function(c,a,b,d,e){return d*((a=a/e-1)*a*a*a*a+1)+b},easeInOutQuint:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a*a+b;return d/2*((a-=2)*a*a*a*a+2)+b},easeInSine:function(c,a,b,d,e){return-d*Math.cos(a/e*(Math.PI/2))+d+b},easeOutSine:function(c,a,b,d,e){return d*Math.sin(a/e*(Math.PI/2))+b},easeInOutSine:function(c,a,b,d,e){return-d/2*(Math.cos(Math.PI*a/e)-1)+
|
||||
b},easeInExpo:function(c,a,b,d,e){return a==0?b:d*Math.pow(2,10*(a/e-1))+b},easeOutExpo:function(c,a,b,d,e){return a==e?b+d:d*(-Math.pow(2,-10*a/e)+1)+b},easeInOutExpo:function(c,a,b,d,e){if(a==0)return b;if(a==e)return b+d;if((a/=e/2)<1)return d/2*Math.pow(2,10*(a-1))+b;return d/2*(-Math.pow(2,-10*--a)+2)+b},easeInCirc:function(c,a,b,d,e){return-d*(Math.sqrt(1-(a/=e)*a)-1)+b},easeOutCirc:function(c,a,b,d,e){return d*Math.sqrt(1-(a=a/e-1)*a)+b},easeInOutCirc:function(c,a,b,d,e){if((a/=e/2)<1)return-d/
|
||||
2*(Math.sqrt(1-a*a)-1)+b;return d/2*(Math.sqrt(1-(a-=2)*a)+1)+b},easeInElastic:function(c,a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e)==1)return b+d;g||(g=e*0.3);if(h<Math.abs(d)){h=d;c=g/4}else c=g/(2*Math.PI)*Math.asin(d/h);return-(h*Math.pow(2,10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g))+b},easeOutElastic:function(c,a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e)==1)return b+d;g||(g=e*0.3);if(h<Math.abs(d)){h=d;c=g/4}else c=g/(2*Math.PI)*Math.asin(d/h);return h*Math.pow(2,-10*
|
||||
a)*Math.sin((a*e-c)*2*Math.PI/g)+d+b},easeInOutElastic:function(c,a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e/2)==2)return b+d;g||(g=e*0.3*1.5);if(h<Math.abs(d)){h=d;c=g/4}else c=g/(2*Math.PI)*Math.asin(d/h);if(a<1)return-0.5*h*Math.pow(2,10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g)+b;return h*Math.pow(2,-10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g)*0.5+d+b},easeInBack:function(c,a,b,d,e,g){if(g==j)g=1.70158;return d*(a/=e)*a*((g+1)*a-g)+b},easeOutBack:function(c,a,b,d,e,g){if(g==j)g=1.70158;
|
||||
return d*((a=a/e-1)*a*((g+1)*a+g)+1)+b},easeInOutBack:function(c,a,b,d,e,g){if(g==j)g=1.70158;if((a/=e/2)<1)return d/2*a*a*(((g*=1.525)+1)*a-g)+b;return d/2*((a-=2)*a*(((g*=1.525)+1)*a+g)+2)+b},easeInBounce:function(c,a,b,d,e){return d-f.easing.easeOutBounce(c,e-a,0,d,e)+b},easeOutBounce:function(c,a,b,d,e){return(a/=e)<1/2.75?d*7.5625*a*a+b:a<2/2.75?d*(7.5625*(a-=1.5/2.75)*a+0.75)+b:a<2.5/2.75?d*(7.5625*(a-=2.25/2.75)*a+0.9375)+b:d*(7.5625*(a-=2.625/2.75)*a+0.984375)+b},easeInOutBounce:function(c,
|
||||
a,b,d,e){if(a<e/2)return f.easing.easeInBounce(c,a*2,0,d,e)*0.5+b;return f.easing.easeOutBounce(c,a*2-e,0,d,e)*0.5+d*0.5+b}})}(jQuery);
|
||||
;/*
|
||||
* jQuery UI Effects Blind 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/Effects/Blind
|
||||
*
|
||||
* Depends:
|
||||
* jquery.effects.core.js
|
||||
*/
|
||||
(function(b){b.effects.blind=function(c){return this.queue(function(){var a=b(this),g=["position","top","left"],f=b.effects.setMode(a,c.options.mode||"hide"),d=c.options.direction||"vertical";b.effects.save(a,g);a.show();var e=b.effects.createWrapper(a).css({overflow:"hidden"}),h=d=="vertical"?"height":"width";d=d=="vertical"?e.height():e.width();f=="show"&&e.css(h,0);var i={};i[h]=f=="show"?d:0;e.animate(i,c.duration,c.options.easing,function(){f=="hide"&&a.hide();b.effects.restore(a,g);b.effects.removeWrapper(a);
|
||||
c.callback&&c.callback.apply(a[0],arguments);a.dequeue()})})}})(jQuery);
|
||||
;/*
|
||||
* jQuery UI Effects Bounce 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/Effects/Bounce
|
||||
*
|
||||
* Depends:
|
||||
* jquery.effects.core.js
|
||||
*/
|
||||
(function(e){e.effects.bounce=function(b){return this.queue(function(){var a=e(this),l=["position","top","left"],h=e.effects.setMode(a,b.options.mode||"effect"),d=b.options.direction||"up",c=b.options.distance||20,m=b.options.times||5,i=b.duration||250;/show|hide/.test(h)&&l.push("opacity");e.effects.save(a,l);a.show();e.effects.createWrapper(a);var f=d=="up"||d=="down"?"top":"left";d=d=="up"||d=="left"?"pos":"neg";c=b.options.distance||(f=="top"?a.outerHeight({margin:true})/3:a.outerWidth({margin:true})/
|
||||
3);if(h=="show")a.css("opacity",0).css(f,d=="pos"?-c:c);if(h=="hide")c/=m*2;h!="hide"&&m--;if(h=="show"){var g={opacity:1};g[f]=(d=="pos"?"+=":"-=")+c;a.animate(g,i/2,b.options.easing);c/=2;m--}for(g=0;g<m;g++){var j={},k={};j[f]=(d=="pos"?"-=":"+=")+c;k[f]=(d=="pos"?"+=":"-=")+c;a.animate(j,i/2,b.options.easing).animate(k,i/2,b.options.easing);c=h=="hide"?c*2:c/2}if(h=="hide"){g={opacity:0};g[f]=(d=="pos"?"-=":"+=")+c;a.animate(g,i/2,b.options.easing,function(){a.hide();e.effects.restore(a,l);e.effects.removeWrapper(a);
|
||||
b.callback&&b.callback.apply(this,arguments)})}else{j={};k={};j[f]=(d=="pos"?"-=":"+=")+c;k[f]=(d=="pos"?"+=":"-=")+c;a.animate(j,i/2,b.options.easing).animate(k,i/2,b.options.easing,function(){e.effects.restore(a,l);e.effects.removeWrapper(a);b.callback&&b.callback.apply(this,arguments)})}a.queue("fx",function(){a.dequeue()});a.dequeue()})}})(jQuery);
|
||||
;/*
|
||||
* jQuery UI Effects Clip 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/Effects/Clip
|
||||
*
|
||||
* Depends:
|
||||
* jquery.effects.core.js
|
||||
*/
|
||||
(function(b){b.effects.clip=function(e){return this.queue(function(){var a=b(this),i=["position","top","left","height","width"],f=b.effects.setMode(a,e.options.mode||"hide"),c=e.options.direction||"vertical";b.effects.save(a,i);a.show();var d=b.effects.createWrapper(a).css({overflow:"hidden"});d=a[0].tagName=="IMG"?d:a;var g={size:c=="vertical"?"height":"width",position:c=="vertical"?"top":"left"};c=c=="vertical"?d.height():d.width();if(f=="show"){d.css(g.size,0);d.css(g.position,c/2)}var h={};h[g.size]=
|
||||
f=="show"?c:0;h[g.position]=f=="show"?0:c/2;d.animate(h,{queue:false,duration:e.duration,easing:e.options.easing,complete:function(){f=="hide"&&a.hide();b.effects.restore(a,i);b.effects.removeWrapper(a);e.callback&&e.callback.apply(a[0],arguments);a.dequeue()}})})}})(jQuery);
|
||||
;/*
|
||||
* jQuery UI Effects Drop 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/Effects/Drop
|
||||
*
|
||||
* Depends:
|
||||
* jquery.effects.core.js
|
||||
*/
|
||||
(function(c){c.effects.drop=function(d){return this.queue(function(){var a=c(this),h=["position","top","left","opacity"],e=c.effects.setMode(a,d.options.mode||"hide"),b=d.options.direction||"left";c.effects.save(a,h);a.show();c.effects.createWrapper(a);var f=b=="up"||b=="down"?"top":"left";b=b=="up"||b=="left"?"pos":"neg";var g=d.options.distance||(f=="top"?a.outerHeight({margin:true})/2:a.outerWidth({margin:true})/2);if(e=="show")a.css("opacity",0).css(f,b=="pos"?-g:g);var i={opacity:e=="show"?1:
|
||||
0};i[f]=(e=="show"?b=="pos"?"+=":"-=":b=="pos"?"-=":"+=")+g;a.animate(i,{queue:false,duration:d.duration,easing:d.options.easing,complete:function(){e=="hide"&&a.hide();c.effects.restore(a,h);c.effects.removeWrapper(a);d.callback&&d.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery);
|
||||
;/*
|
||||
* jQuery UI Effects Explode 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/Effects/Explode
|
||||
*
|
||||
* Depends:
|
||||
* jquery.effects.core.js
|
||||
*/
|
||||
(function(j){j.effects.explode=function(a){return this.queue(function(){var c=a.options.pieces?Math.round(Math.sqrt(a.options.pieces)):3,d=a.options.pieces?Math.round(Math.sqrt(a.options.pieces)):3;a.options.mode=a.options.mode=="toggle"?j(this).is(":visible")?"hide":"show":a.options.mode;var b=j(this).show().css("visibility","hidden"),g=b.offset();g.top-=parseInt(b.css("marginTop"),10)||0;g.left-=parseInt(b.css("marginLeft"),10)||0;for(var h=b.outerWidth(true),i=b.outerHeight(true),e=0;e<c;e++)for(var f=
|
||||
0;f<d;f++)b.clone().appendTo("body").wrap("<div></div>").css({position:"absolute",visibility:"visible",left:-f*(h/d),top:-e*(i/c)}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:h/d,height:i/c,left:g.left+f*(h/d)+(a.options.mode=="show"?(f-Math.floor(d/2))*(h/d):0),top:g.top+e*(i/c)+(a.options.mode=="show"?(e-Math.floor(c/2))*(i/c):0),opacity:a.options.mode=="show"?0:1}).animate({left:g.left+f*(h/d)+(a.options.mode=="show"?0:(f-Math.floor(d/2))*(h/d)),top:g.top+
|
||||
e*(i/c)+(a.options.mode=="show"?0:(e-Math.floor(c/2))*(i/c)),opacity:a.options.mode=="show"?1:0},a.duration||500);setTimeout(function(){a.options.mode=="show"?b.css({visibility:"visible"}):b.css({visibility:"visible"}).hide();a.callback&&a.callback.apply(b[0]);b.dequeue();j("div.ui-effects-explode").remove()},a.duration||500)})}})(jQuery);
|
||||
;/*
|
||||
* jQuery UI Effects Fade 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/Effects/Fade
|
||||
*
|
||||
* Depends:
|
||||
* jquery.effects.core.js
|
||||
*/
|
||||
(function(b){b.effects.fade=function(a){return this.queue(function(){var c=b(this),d=b.effects.setMode(c,a.options.mode||"hide");c.animate({opacity:d},{queue:false,duration:a.duration,easing:a.options.easing,complete:function(){a.callback&&a.callback.apply(this,arguments);c.dequeue()}})})}})(jQuery);
|
||||
;/*
|
||||
* jQuery UI Effects Fold 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/Effects/Fold
|
||||
*
|
||||
* Depends:
|
||||
* jquery.effects.core.js
|
||||
*/
|
||||
(function(c){c.effects.fold=function(a){return this.queue(function(){var b=c(this),j=["position","top","left"],d=c.effects.setMode(b,a.options.mode||"hide"),g=a.options.size||15,h=!!a.options.horizFirst,k=a.duration?a.duration/2:c.fx.speeds._default/2;c.effects.save(b,j);b.show();var e=c.effects.createWrapper(b).css({overflow:"hidden"}),f=d=="show"!=h,l=f?["width","height"]:["height","width"];f=f?[e.width(),e.height()]:[e.height(),e.width()];var i=/([0-9]+)%/.exec(g);if(i)g=parseInt(i[1],10)/100*
|
||||
f[d=="hide"?0:1];if(d=="show")e.css(h?{height:0,width:g}:{height:g,width:0});h={};i={};h[l[0]]=d=="show"?f[0]:g;i[l[1]]=d=="show"?f[1]:0;e.animate(h,k,a.options.easing).animate(i,k,a.options.easing,function(){d=="hide"&&b.hide();c.effects.restore(b,j);c.effects.removeWrapper(b);a.callback&&a.callback.apply(b[0],arguments);b.dequeue()})})}})(jQuery);
|
||||
;/*
|
||||
* jQuery UI Effects Highlight 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/Effects/Highlight
|
||||
*
|
||||
* Depends:
|
||||
* jquery.effects.core.js
|
||||
*/
|
||||
(function(b){b.effects.highlight=function(c){return this.queue(function(){var a=b(this),e=["backgroundImage","backgroundColor","opacity"],d=b.effects.setMode(a,c.options.mode||"show"),f={backgroundColor:a.css("backgroundColor")};if(d=="hide")f.opacity=0;b.effects.save(a,e);a.show().css({backgroundImage:"none",backgroundColor:c.options.color||"#ffff99"}).animate(f,{queue:false,duration:c.duration,easing:c.options.easing,complete:function(){d=="hide"&&a.hide();b.effects.restore(a,e);d=="show"&&!b.support.opacity&&
|
||||
this.style.removeAttribute("filter");c.callback&&c.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery);
|
||||
;/*
|
||||
* jQuery UI Effects Pulsate 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/Effects/Pulsate
|
||||
*
|
||||
* Depends:
|
||||
* jquery.effects.core.js
|
||||
*/
|
||||
(function(d){d.effects.pulsate=function(a){return this.queue(function(){var b=d(this),c=d.effects.setMode(b,a.options.mode||"show");times=(a.options.times||5)*2-1;duration=a.duration?a.duration/2:d.fx.speeds._default/2;isVisible=b.is(":visible");animateTo=0;if(!isVisible){b.css("opacity",0).show();animateTo=1}if(c=="hide"&&isVisible||c=="show"&&!isVisible)times--;for(c=0;c<times;c++){b.animate({opacity:animateTo},duration,a.options.easing);animateTo=(animateTo+1)%2}b.animate({opacity:animateTo},duration,
|
||||
a.options.easing,function(){animateTo==0&&b.hide();a.callback&&a.callback.apply(this,arguments)});b.queue("fx",function(){b.dequeue()}).dequeue()})}})(jQuery);
|
||||
;/*
|
||||
* jQuery UI Effects Scale 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/Effects/Scale
|
||||
*
|
||||
* Depends:
|
||||
* jquery.effects.core.js
|
||||
*/
|
||||
(function(c){c.effects.puff=function(b){return this.queue(function(){var a=c(this),e=c.effects.setMode(a,b.options.mode||"hide"),g=parseInt(b.options.percent,10)||150,h=g/100,i={height:a.height(),width:a.width()};c.extend(b.options,{fade:true,mode:e,percent:e=="hide"?g:100,from:e=="hide"?i:{height:i.height*h,width:i.width*h}});a.effect("scale",b.options,b.duration,b.callback);a.dequeue()})};c.effects.scale=function(b){return this.queue(function(){var a=c(this),e=c.extend(true,{},b.options),g=c.effects.setMode(a,
|
||||
b.options.mode||"effect"),h=parseInt(b.options.percent,10)||(parseInt(b.options.percent,10)==0?0:g=="hide"?0:100),i=b.options.direction||"both",f=b.options.origin;if(g!="effect"){e.origin=f||["middle","center"];e.restore=true}f={height:a.height(),width:a.width()};a.from=b.options.from||(g=="show"?{height:0,width:0}:f);h={y:i!="horizontal"?h/100:1,x:i!="vertical"?h/100:1};a.to={height:f.height*h.y,width:f.width*h.x};if(b.options.fade){if(g=="show"){a.from.opacity=0;a.to.opacity=1}if(g=="hide"){a.from.opacity=
|
||||
1;a.to.opacity=0}}e.from=a.from;e.to=a.to;e.mode=g;a.effect("size",e,b.duration,b.callback);a.dequeue()})};c.effects.size=function(b){return this.queue(function(){var a=c(this),e=["position","top","left","width","height","overflow","opacity"],g=["position","top","left","overflow","opacity"],h=["width","height","overflow"],i=["fontSize"],f=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],k=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"],p=c.effects.setMode(a,
|
||||
b.options.mode||"effect"),n=b.options.restore||false,m=b.options.scale||"both",l=b.options.origin,j={height:a.height(),width:a.width()};a.from=b.options.from||j;a.to=b.options.to||j;if(l){l=c.effects.getBaseline(l,j);a.from.top=(j.height-a.from.height)*l.y;a.from.left=(j.width-a.from.width)*l.x;a.to.top=(j.height-a.to.height)*l.y;a.to.left=(j.width-a.to.width)*l.x}var d={from:{y:a.from.height/j.height,x:a.from.width/j.width},to:{y:a.to.height/j.height,x:a.to.width/j.width}};if(m=="box"||m=="both"){if(d.from.y!=
|
||||
d.to.y){e=e.concat(f);a.from=c.effects.setTransition(a,f,d.from.y,a.from);a.to=c.effects.setTransition(a,f,d.to.y,a.to)}if(d.from.x!=d.to.x){e=e.concat(k);a.from=c.effects.setTransition(a,k,d.from.x,a.from);a.to=c.effects.setTransition(a,k,d.to.x,a.to)}}if(m=="content"||m=="both")if(d.from.y!=d.to.y){e=e.concat(i);a.from=c.effects.setTransition(a,i,d.from.y,a.from);a.to=c.effects.setTransition(a,i,d.to.y,a.to)}c.effects.save(a,n?e:g);a.show();c.effects.createWrapper(a);a.css("overflow","hidden").css(a.from);
|
||||
if(m=="content"||m=="both"){f=f.concat(["marginTop","marginBottom"]).concat(i);k=k.concat(["marginLeft","marginRight"]);h=e.concat(f).concat(k);a.find("*[width]").each(function(){child=c(this);n&&c.effects.save(child,h);var o={height:child.height(),width:child.width()};child.from={height:o.height*d.from.y,width:o.width*d.from.x};child.to={height:o.height*d.to.y,width:o.width*d.to.x};if(d.from.y!=d.to.y){child.from=c.effects.setTransition(child,f,d.from.y,child.from);child.to=c.effects.setTransition(child,
|
||||
f,d.to.y,child.to)}if(d.from.x!=d.to.x){child.from=c.effects.setTransition(child,k,d.from.x,child.from);child.to=c.effects.setTransition(child,k,d.to.x,child.to)}child.css(child.from);child.animate(child.to,b.duration,b.options.easing,function(){n&&c.effects.restore(child,h)})})}a.animate(a.to,{queue:false,duration:b.duration,easing:b.options.easing,complete:function(){a.to.opacity===0&&a.css("opacity",a.from.opacity);p=="hide"&&a.hide();c.effects.restore(a,n?e:g);c.effects.removeWrapper(a);b.callback&&
|
||||
b.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery);
|
||||
;/*
|
||||
* jQuery UI Effects Shake 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/Effects/Shake
|
||||
*
|
||||
* Depends:
|
||||
* jquery.effects.core.js
|
||||
*/
|
||||
(function(d){d.effects.shake=function(a){return this.queue(function(){var b=d(this),j=["position","top","left"];d.effects.setMode(b,a.options.mode||"effect");var c=a.options.direction||"left",e=a.options.distance||20,l=a.options.times||3,f=a.duration||a.options.duration||140;d.effects.save(b,j);b.show();d.effects.createWrapper(b);var g=c=="up"||c=="down"?"top":"left",h=c=="up"||c=="left"?"pos":"neg";c={};var i={},k={};c[g]=(h=="pos"?"-=":"+=")+e;i[g]=(h=="pos"?"+=":"-=")+e*2;k[g]=(h=="pos"?"-=":"+=")+
|
||||
e*2;b.animate(c,f,a.options.easing);for(e=1;e<l;e++)b.animate(i,f,a.options.easing).animate(k,f,a.options.easing);b.animate(i,f,a.options.easing).animate(c,f/2,a.options.easing,function(){d.effects.restore(b,j);d.effects.removeWrapper(b);a.callback&&a.callback.apply(this,arguments)});b.queue("fx",function(){b.dequeue()});b.dequeue()})}})(jQuery);
|
||||
;/*
|
||||
* jQuery UI Effects Slide 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/Effects/Slide
|
||||
*
|
||||
* Depends:
|
||||
* jquery.effects.core.js
|
||||
*/
|
||||
(function(c){c.effects.slide=function(d){return this.queue(function(){var a=c(this),h=["position","top","left"],e=c.effects.setMode(a,d.options.mode||"show"),b=d.options.direction||"left";c.effects.save(a,h);a.show();c.effects.createWrapper(a).css({overflow:"hidden"});var f=b=="up"||b=="down"?"top":"left";b=b=="up"||b=="left"?"pos":"neg";var g=d.options.distance||(f=="top"?a.outerHeight({margin:true}):a.outerWidth({margin:true}));if(e=="show")a.css(f,b=="pos"?-g:g);var i={};i[f]=(e=="show"?b=="pos"?
|
||||
"+=":"-=":b=="pos"?"-=":"+=")+g;a.animate(i,{queue:false,duration:d.duration,easing:d.options.easing,complete:function(){e=="hide"&&a.hide();c.effects.restore(a,h);c.effects.removeWrapper(a);d.callback&&d.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery);
|
||||
;/*
|
||||
* jQuery UI Effects Transfer 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/Effects/Transfer
|
||||
*
|
||||
* Depends:
|
||||
* jquery.effects.core.js
|
||||
*/
|
||||
(function(e){e.effects.transfer=function(a){return this.queue(function(){var b=e(this),c=e(a.options.to),d=c.offset();c={top:d.top,left:d.left,height:c.innerHeight(),width:c.innerWidth()};d=b.offset();var f=e('<div class="ui-effects-transfer"></div>').appendTo(document.body).addClass(a.options.className).css({top:d.top,left:d.left,height:b.innerHeight(),width:b.innerWidth(),position:"absolute"}).animate(c,a.duration,a.options.easing,function(){f.remove();a.callback&&a.callback.apply(b[0],arguments);
|
||||
b.dequeue()})})}})(jQuery);
|
||||
;
|
BIN
resources/content_server/logo.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
resources/content_server/star-half.png
Normal file
After Width: | Height: | Size: 667 B |
BIN
resources/content_server/star-off.png
Normal file
After Width: | Height: | Size: 685 B |
BIN
resources/content_server/star-on.png
Normal file
After Width: | Height: | Size: 631 B |
@ -25,6 +25,9 @@ series_index_auto_increment = 'next'
|
||||
# copy : copy author to author_sort without modification
|
||||
# comma : use 'copy' if there is a ',' in the name, otherwise use 'invert'
|
||||
# nocomma : "fn ln" -> "ln fn" (without the comma)
|
||||
# When this tweak is changed, the author_sort values stored with each author
|
||||
# must be recomputed by right-clicking on an author in the left-hand tags pane,
|
||||
# selecting 'manage authors', and pressing 'Recalculate all author sort values'.
|
||||
author_sort_copy_method = 'invert'
|
||||
|
||||
|
||||
|
BIN
resources/images/news/frazpc.png
Normal file
After Width: | Height: | Size: 631 B |
BIN
resources/images/news/orsai.png
Normal file
After Width: | Height: | Size: 684 B |
BIN
resources/images/news/rstones.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
@ -1,7 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2009, Darko Miletic <darko.miletic at gmail.com>'
|
||||
__copyright__ = '2009-2010, Darko Miletic <darko.miletic at gmail.com>'
|
||||
'''
|
||||
www.business-standard.com
|
||||
'''
|
||||
@ -28,30 +26,22 @@ class BusinessStandard(BasicNewsRecipe):
|
||||
,'publisher' : publisher
|
||||
,'linearize_tables': True
|
||||
}
|
||||
|
||||
remove_attributes=['style']
|
||||
remove_tags = [dict(name=['object','link','script','iframe'])]
|
||||
keep_only_tags=[dict(attrs={'class':'TableClas'})]
|
||||
remove_tags = [
|
||||
dict(name=['object','link','script','iframe','base','meta'])
|
||||
,dict(attrs={'class':'rightDiv2'})
|
||||
,dict(name='table',attrs={'width':'450px'})
|
||||
]
|
||||
remove_attributes=['width','height']
|
||||
|
||||
feeds = [
|
||||
(u'News Now' , u'http://feeds.business-standard.com/News-Now.xml' )
|
||||
,(u'Banking & finance' , u'http://feeds.business-standard.com/Banking-Finance-All.xml' )
|
||||
,(u'Companies & Industry', u'http://feeds.business-standard.com/Companies-Industry-All.xml')
|
||||
,(u'Economy & Policy' , u'http://feeds.business-standard.com/Economy-Policy-All.xml' )
|
||||
,(u'Tech World' , u'http://feeds.business-standard.com/Tech-World-All.xml' )
|
||||
,(u'Life & Leisure' , u'http://feeds.business-standard.com/Life-Leisure-All.xml' )
|
||||
,(u'Markets & Investing' , u'http://feeds.business-standard.com/Markets-Investing-All.xml' )
|
||||
,(u'Management & Mktg' , u'http://feeds.business-standard.com/Management-Mktg-All.xml' )
|
||||
,(u'Automobiles' , u'http://feeds.business-standard.com/Automobiles.xml' )
|
||||
,(u'Aviation' , u'http://feeds.business-standard.com/Aviation.xml' )
|
||||
(u'News Now' , u'http://feeds.business-standard.com/rss/online.xml')
|
||||
,(u'Banking & finance' , u'http://feeds.business-standard.com/rss/3_0.xml' )
|
||||
,(u'Companies & Industry', u'http://feeds.business-standard.com/rss/2_0.xml' )
|
||||
,(u'Economy & Policy' , u'http://feeds.business-standard.com/rss/4_0.xml' )
|
||||
,(u'Tech World' , u'http://feeds.business-standard.com/rss/8_0.xml' )
|
||||
,(u'Life & Leisure' , u'http://feeds.business-standard.com/rss/6_0.xml' )
|
||||
,(u'Markets & Investing' , u'http://feeds.business-standard.com/rss/1_0.xml' )
|
||||
,(u'Management & Mktg' , u'http://feeds.business-standard.com/rss/7_0.xml' )
|
||||
,(u'Opinion' , u'http://feeds.business-standard.com/rss/5_0.xml' )
|
||||
]
|
||||
|
||||
def print_version(self, url):
|
||||
autono = url.rpartition('autono=')[2]
|
||||
tp = 'on'
|
||||
hk = url.rpartition('bKeyFlag=')[1]
|
||||
if hk == '':
|
||||
tp = ''
|
||||
return 'http://www.business-standard.com/india/printpage.php?autono=' + autono + '&tp=' + tp
|
||||
|
||||
def get_article_url(self, article):
|
||||
return article.get('guid', None)
|
||||
|
86
resources/recipes/el_cultural.recipe
Normal file
@ -0,0 +1,86 @@
|
||||
from calibre.web.feeds.recipes import BasicNewsRecipe
|
||||
|
||||
class RevistaElCultural(BasicNewsRecipe):
|
||||
|
||||
title = 'Revista El Cultural'
|
||||
__author__ = 'Jefferson Frantz'
|
||||
description = 'Revista de cultura'
|
||||
timefmt = ' [%d %b, %Y]'
|
||||
language = 'es'
|
||||
|
||||
no_stylesheets = True
|
||||
remove_javascript = True
|
||||
|
||||
extra_css = 'h1{ font-family: sans-serif; font-size: large; font-weight: bolder; text-align: justify } h2{ font-family: sans-serif; font-size: small; font-weight: 500; text-align: justify } h3{ font-family: sans-serif; font-size: small; font-weight: 500; text-align: justify } h4{ font-family: sans-serif; font-weight: lighter; font-size: medium; font-style: italic; text-align: justify } .rtsArticuloFirma{ font-family: sans-serif; font-size: small; text-align: justify } .column span-13 last{ font-family: sans-serif; font-size: medium; text-align: justify } .rtsImgArticulo{font-family: serif; font-size: small; color: #000000; text-align: justify}'
|
||||
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
for item in soup.findAll(style=True):
|
||||
del item['style']
|
||||
|
||||
return soup
|
||||
|
||||
keep_only_tags = [dict(name='div', attrs={'class':['column span-13 last']}),dict(name='div', attrs={'class':['rtsImgArticulo']})]
|
||||
|
||||
remove_tags = [
|
||||
dict(name=['object','link','script','ul'])
|
||||
,dict(name='div', attrs={'class':['rtsRating']})
|
||||
|
||||
]
|
||||
|
||||
|
||||
#TO GET ARTICLES IN SECTION
|
||||
def ec_parse_section(self, url, titleSection):
|
||||
print 'Section: '+ titleSection
|
||||
soup = self.index_to_soup(url)
|
||||
div = soup.find(attrs={'id':'gallery'})
|
||||
current_articles = []
|
||||
|
||||
for a in div.findAllNext('a', href=True):
|
||||
if a is None:
|
||||
continue
|
||||
title = self.tag_to_string(a)
|
||||
|
||||
url = a.get('href', False)
|
||||
if not url or not title:
|
||||
continue
|
||||
|
||||
if not url.startswith('/version_papel/'+titleSection+'/'):
|
||||
if len(current_articles) > 0 and not url.startswith('/secciones/'):
|
||||
break
|
||||
continue
|
||||
|
||||
if url.startswith('/version_papel/'+titleSection+'/'):
|
||||
url = 'http://www.elcultural.es'+url
|
||||
|
||||
self.log('\t\tFound article:', title[0:title.find("|")-1])
|
||||
self.log('\t\t\t', url)
|
||||
current_articles.append({'title': title[0:title.find("|")-1], 'url':url,
|
||||
'description':'', 'date':''})
|
||||
|
||||
return current_articles
|
||||
|
||||
|
||||
# To GET SECTIONS
|
||||
def parse_index(self):
|
||||
feeds = []
|
||||
for title, url in [
|
||||
('LETRAS',
|
||||
'http://www.elcultural.es/pdf_sumario/cultural/Sumario_El_Cultural_en_PDF'),
|
||||
('ARTE',
|
||||
'http://www.elcultural.es/pdf_sumario/cultural/Sumario_El_Cultural_en_PDF'),
|
||||
('CINE',
|
||||
'http://www.elcultural.es/pdf_sumario/cultural/Sumario_El_Cultural_en_PDF'),
|
||||
('CIENCIA',
|
||||
'http://www.elcultural.es/pdf_sumario/cultural/Sumario_El_Cultural_en_PDF'),
|
||||
## ('OPINION',
|
||||
## 'http://www.elcultural.es/pdf_sumario/cultural/Sumario_El_Cultural_en_PDF'),
|
||||
('ESCENARIOS',
|
||||
'http://www.elcultural.es/pdf_sumario/cultural/Sumario_El_Cultural_en_PDF'),
|
||||
]:
|
||||
articles = self.ec_parse_section(url,title)
|
||||
if articles:
|
||||
feeds.append((title, articles))
|
||||
|
||||
|
||||
return feeds
|
@ -1,7 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2009, Darko Miletic <darko.miletic at gmail.com>'
|
||||
__copyright__ = '2009-2010, Darko Miletic <darko.miletic at gmail.com>'
|
||||
'''
|
||||
emol.com
|
||||
'''
|
||||
@ -19,43 +17,34 @@ class ElMercurio(BasicNewsRecipe):
|
||||
no_stylesheets = True
|
||||
use_embedded_content = False
|
||||
encoding = 'cp1252'
|
||||
cover_url = 'http://www.emol.com/especiales/logo_emol/logo_emol.gif'
|
||||
masthead_url = 'http://www.emol.com/especiales/logo_emol/logo_emol.gif'
|
||||
remove_javascript = True
|
||||
use_embedded_content = False
|
||||
language = 'es'
|
||||
|
||||
html2lrf_options = [
|
||||
'--comment', description
|
||||
, '--category', category
|
||||
, '--publisher', publisher
|
||||
]
|
||||
|
||||
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"'
|
||||
conversion_options = {
|
||||
'comment' : description
|
||||
, 'tags' : category
|
||||
, 'publisher' : publisher
|
||||
, 'language' : language
|
||||
}
|
||||
|
||||
keep_only_tags = [
|
||||
dict(name='div', attrs={'class':'despliegue-txt_750px'})
|
||||
,dict(name='div', attrs={'id':'div_cuerpo_participa'})
|
||||
]
|
||||
|
||||
remove_tags = [
|
||||
dict(name='div', attrs={'class':'contenedor_despliegue-col-left300'})
|
||||
,dict(name='div', attrs={'id':['div_centro_dn_opc','div_cabezera','div_secciones','div_contenidos','div_pie','nav']})
|
||||
]
|
||||
keep_only_tags = [dict(name='div', attrs={'id':['cont_iz_titulobajada','cont_iz_creditos_1_a','cont_iz_cuerpo']})]
|
||||
remove_tags = [dict(name='div', attrs={'id':'cont_iz_cuerpo_relacionados'})]
|
||||
remove_attributes = ['height','width']
|
||||
|
||||
feeds = [
|
||||
(u'Noticias de ultima hora', u'http://www.emol.com/rss20/rss.asp?canal=0')
|
||||
,(u'Nacional', u'http://www.emol.com/rss20/rss.asp?canal=1')
|
||||
,(u'Mundo', u'http://www.emol.com/rss20/rss.asp?canal=2')
|
||||
,(u'Deportes', u'http://www.emol.com/rss20/rss.asp?canal=4')
|
||||
,(u'Magazine', u'http://www.emol.com/rss20/rss.asp?canal=6')
|
||||
,(u'Tecnologia', u'http://www.emol.com/rss20/rss.asp?canal=5')
|
||||
,(u'La Musica', u'http://www.emol.com/rss20/rss.asp?canal=7')
|
||||
(u'Noticias de ultima hora', u'http://rss.emol.com/rss.asp?canal=0')
|
||||
,(u'Nacional', u'http://rss.emol.com/rss.asp?canal=1')
|
||||
,(u'Mundo', u'http://rss.emol.com/rss.asp?canal=2')
|
||||
,(u'Deportes', u'http://rss.emol.com/rss.asp?canal=4')
|
||||
,(u'Magazine', u'http://rss.emol.com/rss.asp?canal=6')
|
||||
,(u'Tecnologia', u'http://rss.emol.com/rss.asp?canal=5')
|
||||
]
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
mtag = '<meta http-equiv="Content-Language" content="es-CL"/>'
|
||||
soup.head.insert(0,mtag)
|
||||
for item in soup.findAll(style=True):
|
||||
del item['style']
|
||||
return soup
|
||||
|
||||
language = 'es'
|
||||
|
74
resources/recipes/financial_times_uk.recipe
Normal file
@ -0,0 +1,74 @@
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Darko Miletic <darko.miletic at gmail.com>'
|
||||
'''
|
||||
ft.com
|
||||
'''
|
||||
from calibre import strftime
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class FinancialTimes(BasicNewsRecipe):
|
||||
title = u'Financial Times - UK printed edition'
|
||||
__author__ = 'Darko Miletic'
|
||||
description = 'Financial world news'
|
||||
oldest_article = 2
|
||||
language = 'en_GB'
|
||||
max_articles_per_feed = 250
|
||||
no_stylesheets = True
|
||||
use_embedded_content = False
|
||||
needs_subscription = True
|
||||
encoding = 'utf8'
|
||||
simultaneous_downloads= 1
|
||||
delay = 1
|
||||
LOGIN = 'https://registration.ft.com/registration/barrier/login'
|
||||
INDEX = 'http://www.ft.com/uk-edition'
|
||||
PREFIX = 'http://www.ft.com'
|
||||
|
||||
def get_browser(self):
|
||||
br = BasicNewsRecipe.get_browser()
|
||||
if self.username is not None and self.password is not None:
|
||||
br.open(self.LOGIN)
|
||||
br.select_form(name='loginForm')
|
||||
br['username'] = self.username
|
||||
br['password'] = self.password
|
||||
br.submit()
|
||||
return br
|
||||
|
||||
keep_only_tags = [ dict(name='div', attrs={'id':'cont'}) ]
|
||||
remove_tags_after = dict(name='p', attrs={'class':'copyright'})
|
||||
remove_tags = [
|
||||
dict(name='div', attrs={'id':'floating-con'})
|
||||
,dict(name=['meta','iframe','base','object','embed','link'])
|
||||
]
|
||||
remove_attributes = ['width','height','lang']
|
||||
|
||||
extra_css = """
|
||||
body{font-family:Arial,Helvetica,sans-serif;}
|
||||
h2{font-size:large;}
|
||||
.ft-story-header{font-size:xx-small;}
|
||||
.ft-story-body{font-size:small;}
|
||||
a{color:#003399;}
|
||||
.container{font-size:x-small;}
|
||||
h3{font-size:x-small;color:#003399;}
|
||||
.copyright{font-size: x-small}
|
||||
"""
|
||||
|
||||
def parse_index(self):
|
||||
articles = []
|
||||
soup = self.index_to_soup(self.INDEX)
|
||||
wide = soup.find('div',attrs={'class':'wide'})
|
||||
if wide:
|
||||
for item in wide.findAll('a',href=True):
|
||||
url = self.PREFIX + item['href']
|
||||
title = self.tag_to_string(item)
|
||||
date = strftime(self.timefmt)
|
||||
articles.append({
|
||||
'title' :title
|
||||
,'date' :date
|
||||
,'url' :url
|
||||
,'description':''
|
||||
})
|
||||
return [('FT UK edition',articles)]
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
return self.adeify_images(soup)
|
||||
|
35
resources/recipes/frazpc.recipe
Normal file
@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = u'2010, Tomasz Dlugosz <tomek3d@gmail.com>'
|
||||
'''
|
||||
frazpc.pl
|
||||
'''
|
||||
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
import re
|
||||
class FrazPC(BasicNewsRecipe):
|
||||
title = u'frazpc.pl'
|
||||
publisher = u'frazpc.pl'
|
||||
description = u'Tw\xf3j Vortal Technologiczny'
|
||||
language = 'pl'
|
||||
__author__ = u'Tomasz D\u0142ugosz'
|
||||
oldest_article = 7
|
||||
max_articles_per_feed = 100
|
||||
use_embedded_content = False
|
||||
no_stylesheets = True
|
||||
|
||||
feeds = [(u'Aktualno\u015bci', u'http://www.frazpc.pl/feed'), (u'Recenzje', u'http://www.frazpc.pl/kat/recenzje-2/feed') ]
|
||||
|
||||
keep_only_tags = [dict(name='div', attrs={'id':'FRAZ_CONTENT'})]
|
||||
|
||||
remove_tags = [dict(name='p', attrs={'class':'gray tagsP fs11'})]
|
||||
|
||||
preprocess_regexps = [
|
||||
(re.compile(i[0], re.IGNORECASE | re.DOTALL), i[1]) for i in
|
||||
[(r'<div id="post-[0-9]*"', lambda match: '<div id="FRAZ_CONTENT"'),
|
||||
(r'href="/f/news/', lambda match: 'href="http://www.frazpc.pl/f/news/'),
|
||||
(r' <a href="http://www.frazpc.pl/[^>]*?">(Skomentuj|Komentarz(e)?\([0-9]*\))</a> \|', lambda match: '')]
|
||||
]
|
||||
|
||||
remove_attributes = [ 'width', 'height' ]
|
@ -26,30 +26,11 @@ class GlobeAndMail(BasicNewsRecipe):
|
||||
#credit {margin-top:0px;}
|
||||
.tag {font-size: 22pt;}'''
|
||||
description = 'Canada\'s national newspaper'
|
||||
remove_tags_before = dict(id="article-top")
|
||||
remove_tags = [
|
||||
{'id':['util', 'article-tabs', 'comments', 'article-relations',
|
||||
'gallery-controls', 'video', 'galleryLoading','deck','header',
|
||||
'toolsBottom'] },
|
||||
{'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'}),
|
||||
keep_only_tags = [dict(name='article')]
|
||||
remove_tags = [dict(name='aside'),
|
||||
dict(name='footer'),
|
||||
dict(name='div', attrs={'class':(lambda x: isinstance(x, (str,unicode)) and 'articlecommentcountholder' in x.split(' '))}),
|
||||
dict(name='ul', attrs={'class':(lambda x: isinstance(x, (str,unicode)) and 'articletoolbar' in x.split(' '))}),
|
||||
]
|
||||
feeds = [
|
||||
(u'Latest headlines', u'http://www.theglobeandmail.com/?service=rss'),
|
||||
|
@ -11,8 +11,8 @@ import mechanize
|
||||
class GoComics(BasicNewsRecipe):
|
||||
title = 'GoComics'
|
||||
__author__ = 'Starson17'
|
||||
__version__ = '1.02'
|
||||
__date__ = '14 August 2010'
|
||||
__version__ = '1.03'
|
||||
__date__ = '09 October 2010'
|
||||
description = u'200+ Comics - Customize for more days/comics: Defaults to 7 days, 25 comics - 20 general, 5 editorial.'
|
||||
category = 'news, comics'
|
||||
language = 'en'
|
||||
@ -273,6 +273,7 @@ class GoComics(BasicNewsRecipe):
|
||||
# ("Wit of the World","http://www.gocomics.com/witoftheworld"),
|
||||
# ("Don Wright","http://www.gocomics.com/donwright"),
|
||||
]:
|
||||
print 'Working on: ', title
|
||||
articles = self.make_links(url)
|
||||
if articles:
|
||||
feeds.append((title, articles))
|
||||
@ -286,28 +287,30 @@ class GoComics(BasicNewsRecipe):
|
||||
page_soup = self.index_to_soup(url)
|
||||
if page_soup:
|
||||
try:
|
||||
strip_title = page_soup.h1.a.string
|
||||
strip_title = page_soup.find(name='div', attrs={'class':'top'}).h1.a.string
|
||||
except:
|
||||
strip_title = 'Error - no page_soup.h1.a.string'
|
||||
strip_title = 'Error - no Title found'
|
||||
try:
|
||||
date_title = page_soup.find('ul', attrs={'class': 'feature-nav'}).li.string
|
||||
if not date_title:
|
||||
date_title = page_soup.find('ul', attrs={'class': 'feature-nav'}).li.string
|
||||
except:
|
||||
date_title = 'Error - no page_soup.h1.li.string'
|
||||
date_title = 'Error - no Date found'
|
||||
title = strip_title + ' - ' + date_title
|
||||
for i in range(2):
|
||||
try:
|
||||
strip_url_date = page_soup.h1.a['href']
|
||||
strip_url_date = page_soup.find(name='div', attrs={'class':'top'}).h1.a['href']
|
||||
break #success - this is normal exit
|
||||
except:
|
||||
strip_url_date = None
|
||||
continue #try to get strip_url_date again
|
||||
continue # give up on this strip date
|
||||
for i in range(2):
|
||||
try:
|
||||
prev_strip_url_date = page_soup.find('a', attrs={'class': 'prev'})['href']
|
||||
break #success - this is normal exit
|
||||
except:
|
||||
prev_strip_url_date = None
|
||||
continue #try to get prev_strip_url_date again
|
||||
continue # give up on this prev strip date
|
||||
if strip_url_date:
|
||||
page_url = 'http://www.gocomics.com' + strip_url_date
|
||||
else:
|
||||
|
89
resources/recipes/malaysian_mirror.recipe
Normal file
@ -0,0 +1,89 @@
|
||||
#!/usr/bin/env python
|
||||
__license__ = 'GPL v3'
|
||||
__author__ = 'Tony Stegall'
|
||||
__copyright__ = '2010, Tony Stegall or Tonythebookworm on mobiread.com'
|
||||
__version__ = '1'
|
||||
__date__ = '16, October 2010'
|
||||
__docformat__ = 'English'
|
||||
|
||||
|
||||
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class MalaysianMirror(BasicNewsRecipe):
|
||||
title = 'MalaysianMirror'
|
||||
__author__ = 'Tonythebookworm'
|
||||
description = 'The Pulse of the Nation'
|
||||
language = 'en'
|
||||
no_stylesheets = True
|
||||
publisher = 'Tonythebookworm'
|
||||
category = 'news'
|
||||
use_embedded_content= False
|
||||
no_stylesheets = True
|
||||
oldest_article = 24
|
||||
|
||||
remove_javascript = True
|
||||
remove_empty_feeds = True
|
||||
conversion_options = {'linearize_tables' : True}
|
||||
extra_css = '''
|
||||
#content_heading{font-family:Arial,Helvetica,sans-serif; font-weight:bold;font-size:large;}
|
||||
|
||||
td{text-align:right; font-size:small;margin-top:0px;margin-bottom: 0px;}
|
||||
|
||||
#content_body{font-family:Helvetica,Arial,sans-serif;font-size:small;}
|
||||
'''
|
||||
|
||||
keep_only_tags = [dict(name='table', attrs={'class':['contentpaneopen']})
|
||||
]
|
||||
remove_tags = [dict(name='table', attrs={'class':['buttonheading']})]
|
||||
#######################################################################################################################
|
||||
|
||||
|
||||
max_articles_per_feed = 10
|
||||
|
||||
'''
|
||||
Make a variable that will hold the url for the main site because our links do not include the index
|
||||
'''
|
||||
|
||||
INDEX = 'http://www.malaysianmirror.com'
|
||||
|
||||
|
||||
|
||||
|
||||
def parse_index(self):
|
||||
feeds = []
|
||||
for title, url in [
|
||||
(u"Media Buzz", u"http://www.malaysianmirror.com/media-buzz-front"),
|
||||
(u"Life Style", u"http://www.malaysianmirror.com/lifestylefront"),
|
||||
(u"Features", u"http://www.malaysianmirror.com/featurefront"),
|
||||
|
||||
|
||||
]:
|
||||
articles = self.make_links(url)
|
||||
if articles:
|
||||
feeds.append((title, articles))
|
||||
return feeds
|
||||
|
||||
def make_links(self, url):
|
||||
title = 'Temp'
|
||||
current_articles = []
|
||||
soup = self.index_to_soup(url)
|
||||
# print 'The soup is: ', soup
|
||||
for item in soup.findAll('div', attrs={'class':'contentheading'}):
|
||||
#print 'item is: ', item
|
||||
link = item.find('a')
|
||||
#print 'the link is: ', link
|
||||
if link:
|
||||
url = self.INDEX + link['href']
|
||||
title = self.tag_to_string(link)
|
||||
#print 'the title is: ', title
|
||||
#print 'the url is: ', url
|
||||
#print 'the title is: ', title
|
||||
current_articles.append({'title': title, 'url': url, 'description':'', 'date':''}) # append all this
|
||||
return current_articles
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
for item in soup.findAll(attrs={'style':True}):
|
||||
del item['style']
|
||||
return soup
|
||||
|
@ -1,6 +1,6 @@
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2009, Darko Miletic <darko.miletic at gmail.com>'
|
||||
__copyright__ = '2009-2010, Darko Miletic <darko.miletic at gmail.com>'
|
||||
'''
|
||||
miamiherald.com
|
||||
'''
|
||||
@ -16,12 +16,10 @@ class TheMiamiHerald(BasicNewsRecipe):
|
||||
publisher = u'The Miami Herald'
|
||||
category = u'miami herald, weather, dolphins, news, miami news, local news, miamiherald, miami newspaper, miamiherald.com, miami, the miami herald, broward, miami-dade'
|
||||
language = 'en'
|
||||
|
||||
no_stylesheets = True
|
||||
use_embedded_content = False
|
||||
encoding = 'cp1252'
|
||||
remove_javascript = True
|
||||
|
||||
extra_css = '''
|
||||
h1{font-family:Arial,Helvetica,sans-serif; font-size:large; color:#1A272F; }
|
||||
.subheadline{font-family:Arial,Helvetica,sans-serif; font-size:30%; color: #666666;}
|
||||
@ -33,50 +31,35 @@ class TheMiamiHerald(BasicNewsRecipe):
|
||||
.imageCaption{font-family:Arial,Helvetica,sans-serif; font-size:30%; color:#666666; }
|
||||
'''
|
||||
|
||||
keep_only_tags = [dict(name='div', attrs={'id':['storyBody','storyPhotoContentArea']}),
|
||||
]
|
||||
conversion_options = {
|
||||
'comment' : description
|
||||
, 'tags' : category
|
||||
, 'publisher' : publisher
|
||||
, 'language' : language
|
||||
}
|
||||
|
||||
remove_tags = [dict(name=['object','link','embed']),
|
||||
dict(name='div', attrs={'class':["imageBuyButton","shareLinksArea","storyTools","spill_navigation pagination","circPromoArea","storyTools_footer","storyYahooContentMatch"]}) ,
|
||||
dict(name='div', attrs={'id':["pluck","mlt","storyAssets"]}) ]
|
||||
keep_only_tags = [dict(name='div', attrs={'id':'wide'}),]
|
||||
|
||||
remove_tags = [dict(name=['object','link','embed','iframe','meta'])]
|
||||
|
||||
|
||||
feeds = [
|
||||
(u'Breaking News' , u'http://www.miamiherald.com/416/index.xml' )
|
||||
,(u'Miami-Dade' , u'http://www.miamiherald.com/460/index.xml' )
|
||||
,(u'Broward' , u'http://www.miamiherald.com/467/index.xml' )
|
||||
,(u'Florida Keys' , u'http://www.miamiherald.com/505/index.xml' )
|
||||
,(u'Florida' , u'http://www.miamiherald.com/569/index.xml' )
|
||||
,(u'Nation' , u'http://www.miamiherald.com/509/index.xml' )
|
||||
,(u'World' , u'http://www.miamiherald.com/578/index.xml' )
|
||||
,(u'Americas' , u'http://www.miamiherald.com/579/index.xml' )
|
||||
,(u'Cuba' , u'http://www.miamiherald.com/581/index.xml' )
|
||||
,(u'Haiti' , u'http://www.miamiherald.com/582/index.xml' )
|
||||
,(u'Politics' , u'http://www.miamiherald.com/515/index.xml' )
|
||||
,(u'Education' , u'http://www.miamiherald.com/295/index.xml' )
|
||||
,(u'Environment' , u'http://www.miamiherald.com/573/index.xml' )
|
||||
(u'Breaking News' , u'http://www.miamiherald.com/news/breaking-news/index.xml' )
|
||||
,(u'Miami-Dade' , u'http://www.miamiherald.com/news/miami-dade/index.xml' )
|
||||
,(u'Broward' , u'http://www.miamiherald.com/news/broward/index.xml' )
|
||||
,(u'Florida Keys' , u'http://www.miamiherald.com/news/florida-keys/index.xml' )
|
||||
,(u'Florida' , u'http://www.miamiherald.com/news/florida/index.xml' )
|
||||
,(u'Nation' , u'http://www.miamiherald.com/news/nation/index.xml' )
|
||||
,(u'World' , u'http://www.miamiherald.com/news/world/index.xml' )
|
||||
,(u'Americas' , u'http://www.miamiherald.com/news/americas/index.xml' )
|
||||
,(u'Cuba' , u'http://www.miamiherald.com/news/americas/cuba/index.xml' )
|
||||
,(u'Haiti' , u'http://www.miamiherald.com/news/americas/haiti/index.xml' )
|
||||
,(u'Politics' , u'http://www.miamiherald.com/news/politics/index.xml' )
|
||||
,(u'Education' , u'http://www.miamiherald.com/news/education/index.xml' )
|
||||
,(u'Environment' , u'http://www.miamiherald.com/news/environment/index.xml' )
|
||||
]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def get_article_url(self, article):
|
||||
ans = article.get('guid', None)
|
||||
print ans
|
||||
try:
|
||||
self.log('Looking for full story link in', ans)
|
||||
soup = self.index_to_soup(ans)
|
||||
x = soup.find(text="Full Story")
|
||||
|
||||
if x is not None:
|
||||
a = x.parent
|
||||
if a and a.has_key('href'):
|
||||
ans = 'http://www.miamiherald.com'+a['href']
|
||||
self.log('Found full story link', ans)
|
||||
except:
|
||||
pass
|
||||
return ans
|
||||
|
||||
|
||||
|
||||
def print_version(self, url):
|
||||
art, sep, rest = url.rpartition('/')
|
||||
art2, sep2, rest2 = art.rpartition('/')
|
||||
return art2 + '/v-print/' + rest2 + '/' + rest
|
||||
|
@ -33,10 +33,14 @@ class NewYorker(BasicNewsRecipe):
|
||||
, 'language' : language
|
||||
}
|
||||
|
||||
keep_only_tags = [dict(name='div', attrs={'id':['articleheads','articleRail','articletext','photocredits']})]
|
||||
keep_only_tags = [
|
||||
dict(name='div', attrs={'class':'headers'})
|
||||
,dict(name='div', attrs={'id':['articleheads','items-container','articleRail','articletext','photocredits']})
|
||||
]
|
||||
remove_tags = [
|
||||
dict(name=['meta','iframe','base','link','embed','object'])
|
||||
,dict(name='div', attrs={'class':['utils','articleRailLinks','icons'] })
|
||||
,dict(attrs={'class':['utils','articleRailLinks','icons'] })
|
||||
,dict(attrs={'id':['show-header','show-footer'] })
|
||||
]
|
||||
remove_attributes = ['lang']
|
||||
feeds = [(u'The New Yorker', u'http://feeds.newyorker.com/services/rss/feeds/everything.xml')]
|
||||
|
18
resources/recipes/novaya_gazeta.recipe
Normal file
@ -0,0 +1,18 @@
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class AdvancedUserRecipe1286819935(BasicNewsRecipe):
|
||||
title = u'Novaya Gazeta'
|
||||
__author__ = 'muwa'
|
||||
oldest_article = 7
|
||||
max_articles_per_feed = 100
|
||||
no_stylesheets = True
|
||||
conversion_options = {'linearize_tables' : True}
|
||||
remove_attributes = ['style']
|
||||
language = 'ru'
|
||||
|
||||
feeds = [(u'Articles', u'http://www.novayagazeta.ru/rss_number.xml')]
|
||||
|
||||
|
||||
def print_version(self, url):
|
||||
return url + '?print=true'
|
||||
|
37
resources/recipes/orsai.recipe
Normal 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)
|
||||
|
82
resources/recipes/rstones.recipe
Normal file
@ -0,0 +1,82 @@
|
||||
#!/usr/bin/env python
|
||||
__license__ = 'GPL v3'
|
||||
__author__ = 'Tony Stegall'
|
||||
__copyright__ = '2010, Tony Stegall or Tonythebookworm on mobileread.com'
|
||||
__version__ = 'v1.01'
|
||||
__date__ = '07, October 2010'
|
||||
__description__ = 'Rolling Stones Mag'
|
||||
|
||||
'''
|
||||
http://www.rollingstone.com
|
||||
'''
|
||||
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class RollingStones(BasicNewsRecipe):
|
||||
__author__ = 'Tony Stegall'
|
||||
description = 'Rolling Stones Mag'
|
||||
cover_url = 'http://gallery.celebritypro.com/data/media/648/kid-rock-rolling-stone-cover.jpg'
|
||||
masthead_url = 'http://origin.myfonts.com/s/ec/cc-200804/Rolling_Stone-logo.gif'
|
||||
|
||||
|
||||
title = 'Rolling Stones Mag'
|
||||
category = 'Music Reviews, Movie Reviews, entertainment news'
|
||||
|
||||
language = 'en'
|
||||
timefmt = '[%a, %d %b, %Y]'
|
||||
|
||||
oldest_article = 15
|
||||
max_articles_per_feed = 25
|
||||
use_embedded_content = False
|
||||
no_stylesheets = True
|
||||
|
||||
remove_javascript = True
|
||||
#####################################################################################
|
||||
# cleanup section #
|
||||
#####################################################################################
|
||||
keep_only_tags = [
|
||||
dict(name='div', attrs={'class':['c65l']}),
|
||||
dict(name='div', attrs={'id':['col1']}),
|
||||
|
||||
|
||||
]
|
||||
remove_tags = [
|
||||
dict(name='div', attrs={'class': ['storyActions upper','storyActions lowerArticleNav']}),
|
||||
dict(name='div', attrs={'id': ['comments','related']}),
|
||||
]
|
||||
|
||||
|
||||
feeds = [
|
||||
(u'News', u'http://www.rollingstone.com/siteServices/rss/allNews'),
|
||||
(u'Blogs', u'http://www.rollingstone.com/siteServices/rss/allBlogs'),
|
||||
(u'Movie Reviews', u'http://www.rollingstone.com/siteServices/rss/movieReviews'),
|
||||
(u'Album Reviews', u'http://www.rollingstone.com/siteServices/rss/albumReviews'),
|
||||
(u'Song Reviews', u'http://www.rollingstone.com/siteServices/rss/songReviews'),
|
||||
|
||||
|
||||
]
|
||||
|
||||
|
||||
|
||||
def get_article_url(self, article):
|
||||
return article.get('guid', None)
|
||||
|
||||
|
||||
def append_page(self, soup, appendtag, position):
|
||||
'''
|
||||
Some are the articles are multipage so the below function
|
||||
will get the articles that have <next>
|
||||
'''
|
||||
pager = soup.find('li',attrs={'class':'next'})
|
||||
if pager:
|
||||
nexturl = pager.a['href']
|
||||
soup2 = self.index_to_soup(nexturl)
|
||||
texttag = soup2.find('div', attrs={'id':'storyTextContainer'})
|
||||
for it in texttag.findAll(style=True):
|
||||
del it['style']
|
||||
newpos = len(texttag.contents)
|
||||
self.append_page(soup2,texttag,newpos)
|
||||
texttag.extract()
|
||||
appendtag.insert(position,texttag)
|
||||
|
||||
|
@ -6,7 +6,19 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
'''
|
||||
Modified by Tony Stegall
|
||||
on 10/10/10 to include function to grab print version of articles
|
||||
'''
|
||||
|
||||
from datetime import date
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
'''
|
||||
added by Tony Stegall
|
||||
'''
|
||||
#######################################################
|
||||
from calibre.ptempfile import PersistentTemporaryFile
|
||||
#######################################################
|
||||
|
||||
class AdvancedUserRecipe1249039563(BasicNewsRecipe):
|
||||
title = u'De Volkskrant'
|
||||
@ -16,20 +28,58 @@ class AdvancedUserRecipe1249039563(BasicNewsRecipe):
|
||||
no_stylesheets = True
|
||||
language = 'nl'
|
||||
|
||||
keep_only_tags = [dict(name='div', attrs={'id':'leftColumnArticle'}) ]
|
||||
remove_tags = [
|
||||
dict(name='div',attrs={'class':'article_tools'}),
|
||||
dict(name='div',attrs={'id':'article_tools'}),
|
||||
dict(name='div',attrs={'class':'articletools'}),
|
||||
dict(name='div',attrs={'id':'articletools'}),
|
||||
dict(name='div',attrs={'id':'myOverlay'}),
|
||||
dict(name='div',attrs={'id':'trackback'}),
|
||||
dict(name='div',attrs={'id':'googleBanner'}),
|
||||
dict(name='div',attrs={'id':'article_headlines'}),
|
||||
]
|
||||
extra_css = '''
|
||||
body{font-family:Arial,Helvetica,sans-serif; font-size:small;}
|
||||
h1{font-size:large;}
|
||||
'''
|
||||
'''
|
||||
Change Log:
|
||||
Date: 10/10/10 - Modified code to include obfuscated to get the print version
|
||||
Author: Tony Stegall
|
||||
'''
|
||||
#######################################################################################################
|
||||
temp_files = []
|
||||
articles_are_obfuscated = True
|
||||
|
||||
feeds = [(u'Laatste Nieuws', u'http://volkskrant.nl/rss/laatstenieuws.rss'), (u'Binnenlands nieuws', u'http://volkskrant.nl/rss/nederland.rss'), (u'Buitenlands nieuws', u'http://volkskrant.nl/rss/internationaal.rss'), (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'), (u'Wetenschapsnieuws', u'http://feeds.feedburner.com/DeVolkskrantWetenschap'), (u'Technologienieuws', u'http://feeds.feedburner.com/vkmedia')]
|
||||
def get_obfuscated_article(self, url):
|
||||
br = self.get_browser()
|
||||
print 'THE CURRENT URL IS: ', url
|
||||
br.open(url)
|
||||
year = date.today().year
|
||||
|
||||
try:
|
||||
response = br.follow_link(url_regex='.*?(%d)(\\/)(article)(\\/)(print)(\\/)'%year, nr = 0)
|
||||
html = response.read()
|
||||
except:
|
||||
response = br.open(url)
|
||||
html = response.read()
|
||||
|
||||
self.temp_files.append(PersistentTemporaryFile('_fa.html'))
|
||||
self.temp_files[-1].write(html)
|
||||
self.temp_files[-1].close()
|
||||
return self.temp_files[-1].name
|
||||
|
||||
###############################################################################################################
|
||||
|
||||
'''
|
||||
Change Log:
|
||||
Date: 10/15/2010
|
||||
Feeds updated by Martin Tarenskeen
|
||||
'''
|
||||
|
||||
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') ]
|
||||
|
||||
|
||||
'''
|
||||
example for formating
|
||||
'''
|
||||
# original url: http://www.volkskrant.nl/vk/nl/2668/Buitenland/article/detail/1031493/2010/10/10/Noord-Korea-ziet-nieuwe-leider.dhtml
|
||||
# print url : http://www.volkskrant.nl/vk/nl/2668/2010/article/print/detail/1031493/Noord-Korea-ziet-nieuwe-leider.dhtml
|
||||
|
@ -17,6 +17,7 @@ function selector(elem) {
|
||||
sel = selector_in_parent(obj) + sel;
|
||||
obj = obj.parent();
|
||||
}
|
||||
if (sel.length > 2 && sel.charAt(1) == ">") sel = sel.substring(2);
|
||||
return sel;
|
||||
}
|
||||
|
||||
@ -26,7 +27,8 @@ function calculate_bookmark(y, node) {
|
||||
var ratio = (y - elem.offset().top)/elem.height();
|
||||
if (ratio > 1) { ratio = 1; }
|
||||
if (ratio < 0) { ratio = 0; }
|
||||
return sel + "|" + ratio;
|
||||
sel = sel + "|" + ratio;
|
||||
return sel;
|
||||
}
|
||||
|
||||
function animated_scrolling_done() {
|
||||
@ -37,6 +39,10 @@ function scroll_to_bookmark(bookmark) {
|
||||
bm = bookmark.split("|");
|
||||
var ratio = 0.7 * parseFloat(bm[1]);
|
||||
$.scrollTo($(bm[0]), 1000,
|
||||
{over:ratio, onAfter:function(){window.py_bridge.animated_scroll_done()}});
|
||||
{
|
||||
over:ratio,
|
||||
onAfter:function(){window.py_bridge.animated_scroll_done()}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
89
resources/viewer/jquery_scrollTo.js
vendored
@ -1,15 +1,15 @@
|
||||
/**
|
||||
* jQuery.ScrollTo
|
||||
* Copyright (c) 2007-2008 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
|
||||
* Copyright (c) 2007-2009 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
|
||||
* Dual licensed under MIT and GPL.
|
||||
* Date: 9/11/2008
|
||||
* Date: 5/25/2009
|
||||
*
|
||||
* @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.
|
||||
* Works with jQuery +1.2.6. Tested on FF 2/3, IE 6/7/8, Opera 9.5/6, Safari 3, Chrome 1 on WinXP.
|
||||
*
|
||||
* @author Ariel Flesler
|
||||
* @version 1.4
|
||||
* @version 1.4.2
|
||||
*
|
||||
* @id jQuery.scrollTo
|
||||
* @id jQuery.fn.scrollTo
|
||||
@ -20,6 +20,8 @@
|
||||
* - 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.
|
||||
* - A percentage of the container's dimension/s, for example: 50% to go to the middle.
|
||||
* - The string 'max' for go-to-end.
|
||||
* @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'.
|
||||
@ -58,31 +60,31 @@
|
||||
};
|
||||
|
||||
$scrollTo.defaults = {
|
||||
axis:'y',
|
||||
duration:1
|
||||
axis:'xy',
|
||||
duration: parseFloat($.fn.jquery) >= 1.3 ? 0 : 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();
|
||||
return $(window)._scrollable();
|
||||
};
|
||||
|
||||
// Hack, hack, hack... stay away!
|
||||
// Hack, hack, hack :)
|
||||
// Returns the real elements to scroll (supports window/iframes, documents and regular nodes)
|
||||
$.fn.scrollable = function(){
|
||||
$.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;
|
||||
var elem = this,
|
||||
isWin = !elem.nodeName || $.inArray( elem.nodeName.toLowerCase(), ['iframe','#document','html','body'] ) != -1;
|
||||
|
||||
return elem.nodeName == 'IFRAME' || isWin && $.browser.safari ? doc.body
|
||||
: isWin ? doc.documentElement
|
||||
: this;
|
||||
if( !isWin )
|
||||
return elem;
|
||||
|
||||
var doc = (elem.contentWindow || elem).document || elem.ownerDocument || elem;
|
||||
|
||||
return $.browser.safari || doc.compatMode == 'BackCompat' ?
|
||||
doc.body :
|
||||
doc.documentElement;
|
||||
});
|
||||
};
|
||||
|
||||
@ -94,6 +96,9 @@
|
||||
if( typeof settings == 'function' )
|
||||
settings = { onAfter:settings };
|
||||
|
||||
if( target == 'max' )
|
||||
target = 9e9;
|
||||
|
||||
settings = $.extend( {}, $scrollTo.defaults, settings );
|
||||
// Speed is still recognized for backwards compatibility
|
||||
duration = duration || settings.speed || settings.duration;
|
||||
@ -106,7 +111,7 @@
|
||||
settings.offset = both( settings.offset );
|
||||
settings.over = both( settings.over );
|
||||
|
||||
return this.scrollable().each(function(){
|
||||
return this._scrollable().each(function(){
|
||||
var elem = this,
|
||||
$elem = $(elem),
|
||||
targ = target, toff, attr = {},
|
||||
@ -116,7 +121,7 @@
|
||||
// A number will pass the regex
|
||||
case 'number':
|
||||
case 'string':
|
||||
if( /^([+-]=)?\d+(px)?$/.test(targ) ){
|
||||
if( /^([+-]=)?\d+(\.\d+)?(px|%)?$/.test(targ) ){
|
||||
targ = both( targ );
|
||||
// We are done
|
||||
break;
|
||||
@ -134,8 +139,7 @@
|
||||
pos = Pos.toLowerCase(),
|
||||
key = 'scroll' + Pos,
|
||||
old = elem[key],
|
||||
Dim = axis == 'x' ? 'Width' : 'Height',
|
||||
dim = Dim.toLowerCase();
|
||||
max = $scrollTo.max(elem, axis);
|
||||
|
||||
if( toff ){// jQuery / DOMElement
|
||||
attr[key] = toff[pos] + ( win ? 0 : old - $elem.offset()[pos] );
|
||||
@ -150,14 +154,19 @@
|
||||
|
||||
if( settings.over[pos] )
|
||||
// Scroll to a fraction of its width/height
|
||||
attr[key] += targ[dim]() * settings.over[pos];
|
||||
}else
|
||||
attr[key] = targ[pos];
|
||||
attr[key] += targ[axis=='x'?'width':'height']() * settings.over[pos];
|
||||
}else{
|
||||
var val = targ[pos];
|
||||
// Handle percentage values
|
||||
attr[key] = val.slice && val.slice(-1) == '%' ?
|
||||
parseFloat(val) / 100 * max
|
||||
: val;
|
||||
}
|
||||
|
||||
// Number or 'number'
|
||||
if( /^\d+$/.test(attr[key]) )
|
||||
// Check the limits
|
||||
attr[key] = attr[key] <= 0 ? 0 : Math.min( attr[key], max(Dim) );
|
||||
attr[key] = attr[key] <= 0 ? 0 : Math.min( attr[key], max );
|
||||
|
||||
// Queueing axes
|
||||
if( !i && settings.queue ){
|
||||
@ -169,6 +178,7 @@
|
||||
delete attr[key];
|
||||
}
|
||||
});
|
||||
|
||||
animate( settings.onAfter );
|
||||
|
||||
function animate( callback ){
|
||||
@ -176,17 +186,28 @@
|
||||
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();
|
||||
};
|
||||
|
||||
// Max scrolling position, works on quirks mode
|
||||
// It only fails (not too badly) on IE, quirks mode.
|
||||
$scrollTo.max = function( elem, axis ){
|
||||
var Dim = axis == 'x' ? 'Width' : 'Height',
|
||||
scroll = 'scroll'+Dim;
|
||||
|
||||
if( !$(elem).is('html,body') )
|
||||
return elem[scroll] - $(elem)[Dim.toLowerCase()]();
|
||||
|
||||
var size = 'client' + Dim,
|
||||
html = elem.ownerDocument.documentElement,
|
||||
body = elem.ownerDocument.body;
|
||||
|
||||
return Math.max( html[scroll], body[scroll] )
|
||||
- Math.min( html[size] , body[size] );
|
||||
|
||||
};
|
||||
|
||||
function both( val ){
|
||||
return typeof val == 'object' ? val : { top:val, left:val };
|
||||
};
|
||||
|
@ -19,7 +19,7 @@ __all__ = [
|
||||
'upload_user_manual', 'upload_to_mobileread', 'upload_demo',
|
||||
'upload_to_sourceforge', 'upload_to_google_code',
|
||||
'linux32', 'linux64', 'linux', 'linux_freeze', 'linux_freeze2',
|
||||
'osx32_freeze', 'osx32', 'osx', 'rsync',
|
||||
'osx32_freeze', 'osx32', 'osx', 'rsync', 'push',
|
||||
'win32_freeze', 'win32', 'win',
|
||||
'stage1', 'stage2', 'stage3', 'stage4', 'publish'
|
||||
]
|
||||
@ -68,8 +68,9 @@ upload_to_server = UploadToServer()
|
||||
upload_to_sourceforge = UploadToSourceForge()
|
||||
upload_to_google_code = UploadToGoogleCode()
|
||||
|
||||
from setup.installer import Rsync
|
||||
from setup.installer import Rsync, Push
|
||||
rsync = Rsync()
|
||||
push = Push()
|
||||
|
||||
from setup.installer.linux import Linux, Linux32, Linux64
|
||||
linux = Linux()
|
||||
|
@ -11,16 +11,21 @@ import subprocess, tempfile, os, time
|
||||
from setup import Command, installer_name
|
||||
from setup.build_environment import HOST, PROJECT
|
||||
|
||||
BASE_RSYNC = 'rsync -avz --delete'.split()
|
||||
EXCLUDES = []
|
||||
for x in [
|
||||
'src/calibre/plugins', 'src/calibre/manual', 'src/calibre/trac',
|
||||
'.bzr', '.build', '.svn', 'build', 'dist', 'imgsrc', '*.pyc', '*.pyo', '*.swp',
|
||||
'*.swo']:
|
||||
EXCLUDES.extend(['--exclude', x])
|
||||
SAFE_EXCLUDES = ['"%s"'%x if '*' in x else x for x in EXCLUDES]
|
||||
|
||||
class Rsync(Command):
|
||||
|
||||
description = 'Sync source tree from development machine'
|
||||
|
||||
SYNC_CMD = ('rsync -avz --delete --exclude src/calibre/plugins '
|
||||
'--exclude src/calibre/manual --exclude src/calibre/trac '
|
||||
'--exclude .bzr --exclude .build --exclude .svn --exclude build --exclude dist '
|
||||
'--exclude imgsrc '
|
||||
'--exclude "*.pyc" --exclude "*.pyo" --exclude "*.swp" --exclude "*.swo" '
|
||||
'rsync://{host}/work/{project} ..')
|
||||
SYNC_CMD = ' '.join(BASE_RSYNC+SAFE_EXCLUDES+
|
||||
['rsync://{host}/work/{project}', '..'])
|
||||
|
||||
def run(self, opts):
|
||||
cmd = self.SYNC_CMD.format(host=HOST, project=PROJECT)
|
||||
@ -28,6 +33,27 @@ class Rsync(Command):
|
||||
subprocess.check_call(cmd, shell=True)
|
||||
|
||||
|
||||
class Push(Command):
|
||||
|
||||
description = 'Push code to another host'
|
||||
|
||||
def run(self, opts):
|
||||
from threading import Thread
|
||||
threads = []
|
||||
for host in (
|
||||
r'Owner@winxp:/cygdrive/c/Documents\ and\ Settings/Owner/calibre',
|
||||
'kovid@ox:calibre'
|
||||
):
|
||||
rcmd = BASE_RSYNC + EXCLUDES + ['.', host]
|
||||
print '\n\nPushing to:', host, '\n'
|
||||
threads.append(Thread(target=subprocess.check_call, args=(rcmd,)))
|
||||
threads[-1].start()
|
||||
subprocess.check_call(rcmd)
|
||||
for thread in threads:
|
||||
thread.join()
|
||||
|
||||
|
||||
|
||||
class VMInstaller(Command):
|
||||
|
||||
EXTRA_SLEEP = 5
|
||||
|
@ -2,7 +2,7 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
__appname__ = 'calibre'
|
||||
__version__ = '0.7.23'
|
||||
__version__ = '0.7.24'
|
||||
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>"
|
||||
|
||||
import re
|
||||
|
@ -120,6 +120,11 @@ class InputFormatPlugin(Plugin):
|
||||
#: to make its output suitable for viewing
|
||||
for_viewer = False
|
||||
|
||||
#: The encoding that this input plugin creates files in. A value of
|
||||
#: None means that the encoding is undefined and must be
|
||||
#: detected individually
|
||||
output_encoding = 'utf-8'
|
||||
|
||||
#: Options shared by all Input format plugins. Do not override
|
||||
#: in sub-classes. Use :attr:`options` instead. Every option must be an
|
||||
#: instance of :class:`OptionRecommendation`.
|
||||
|
@ -13,7 +13,8 @@ from calibre.devices.errors import UserFeedback
|
||||
from calibre.devices.usbms.deviceconfig import DeviceConfig
|
||||
from calibre.devices.interface import DevicePlugin
|
||||
from calibre.ebooks.BeautifulSoup import BeautifulSoup
|
||||
from calibre.ebooks.metadata import authors_to_string, MetaInformation
|
||||
from calibre.ebooks.metadata import authors_to_string, MetaInformation, \
|
||||
title_sort
|
||||
from calibre.ebooks.metadata.book.base import Metadata
|
||||
from calibre.ebooks.metadata.epub import set_metadata
|
||||
from calibre.library.server.utils import strftime
|
||||
@ -96,6 +97,9 @@ class ITUNES(DriverBase):
|
||||
|
||||
OPEN_FEEDBACK_MESSAGE = _(
|
||||
'Apple device detected, launching iTunes, please wait ...')
|
||||
BACKLOADING_ERROR_MESSAGE = _(
|
||||
"Cannot copy books directly from iDevice. "
|
||||
"Drag from iTunes Library to desktop, then add to calibre's Library window.")
|
||||
|
||||
# Product IDs:
|
||||
# 0x1291 iPod Touch
|
||||
@ -3128,6 +3132,9 @@ class Book(Metadata):
|
||||
See ebooks.metadata.book.base
|
||||
'''
|
||||
def __init__(self,title,author):
|
||||
|
||||
Metadata.__init__(self, title, authors=[author])
|
||||
|
||||
@property
|
||||
def title_sorter(self):
|
||||
return title_sort(self.title)
|
||||
|
||||
|
@ -39,6 +39,10 @@ class DevicePlugin(Plugin):
|
||||
#: Whether the metadata on books can be set via the GUI.
|
||||
CAN_SET_METADATA = ['title', 'authors', 'collections']
|
||||
|
||||
# Set this to None if the books on the device are files that the GUI can
|
||||
# access in order to add the books from the device to the library
|
||||
BACKLOADING_ERROR_MESSAGE = _('Cannot get files from this device')
|
||||
|
||||
#: Path separator for paths to books on device
|
||||
path_sep = os.sep
|
||||
|
||||
|
@ -36,8 +36,8 @@ class KOBO(USBMS):
|
||||
PRODUCT_ID = [0x4161]
|
||||
BCD = [0x0110]
|
||||
|
||||
VENDOR_NAME = 'KOBO_INC'
|
||||
WINDOWS_MAIN_MEM = WINDOWS_CARD_A_MEM = '.KOBOEREADER'
|
||||
VENDOR_NAME = ['KOBO_INC', 'KOBO']
|
||||
WINDOWS_MAIN_MEM = WINDOWS_CARD_A_MEM = ['.KOBOEREADER', 'EREADER']
|
||||
|
||||
EBOOK_DIR_MAIN = ''
|
||||
SUPPORTS_SUB_DIRS = True
|
||||
|
88
src/calibre/devices/udisks.py
Normal file
@ -0,0 +1,88 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import dbus
|
||||
import os
|
||||
|
||||
def node_mountpoint(node):
|
||||
|
||||
def de_mangle(raw):
|
||||
return raw.replace('\\040', ' ').replace('\\011', '\t').replace('\\012',
|
||||
'\n').replace('\\0134', '\\')
|
||||
|
||||
for line in open('/proc/mounts').readlines():
|
||||
line = line.split()
|
||||
if line[0] == node:
|
||||
return de_mangle(line[1])
|
||||
return None
|
||||
|
||||
|
||||
class UDisks(object):
|
||||
|
||||
def __init__(self):
|
||||
if os.environ.get('CALIBRE_DISABLE_UDISKS', False):
|
||||
raise Exception('User has aborted use of UDISKS')
|
||||
self.bus = dbus.SystemBus()
|
||||
self.main = dbus.Interface(self.bus.get_object('org.freedesktop.UDisks',
|
||||
'/org/freedesktop/UDisks'), 'org.freedesktop.UDisks')
|
||||
|
||||
def device(self, device_node_path):
|
||||
devpath = self.main.FindDeviceByDeviceFile(device_node_path)
|
||||
return dbus.Interface(self.bus.get_object('org.freedesktop.UDisks',
|
||||
devpath), 'org.freedesktop.UDisks.Device')
|
||||
|
||||
def mount(self, device_node_path):
|
||||
d = self.device(device_node_path)
|
||||
try:
|
||||
return unicode(d.FilesystemMount('',
|
||||
['auth_no_user_interaction', 'rw', 'noexec', 'nosuid',
|
||||
'sync', 'nodev', 'uid=1000', 'gid=1000']))
|
||||
except:
|
||||
# May be already mounted, check
|
||||
mp = node_mountpoint(str(device_node_path))
|
||||
if mp is None:
|
||||
raise
|
||||
return mp
|
||||
|
||||
def unmount(self, device_node_path):
|
||||
d = self.device(device_node_path)
|
||||
d.FilesystemUnmount(['force'])
|
||||
|
||||
def eject(self, device_node_path):
|
||||
parent = device_node_path
|
||||
while parent[-1] in '0123456789':
|
||||
parent = parent[:-1]
|
||||
devices = [str(x) for x in self.main.EnumerateDeviceFiles()]
|
||||
for d in devices:
|
||||
if d.startswith(parent) and d != parent:
|
||||
try:
|
||||
self.unmount(d)
|
||||
except:
|
||||
import traceback
|
||||
print 'Failed to unmount:', d
|
||||
traceback.print_exc()
|
||||
d = self.device(parent)
|
||||
d.DriveEject([])
|
||||
|
||||
def mount(node_path):
|
||||
u = UDisks()
|
||||
u.mount(node_path)
|
||||
|
||||
def eject(node_path):
|
||||
u = UDisks()
|
||||
u.eject(node_path)
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
dev = sys.argv[1]
|
||||
print 'Testing with node', dev
|
||||
u = UDisks()
|
||||
print 'Mounted at:', u.mount(dev)
|
||||
print 'Ejecting'
|
||||
u.eject(dev)
|
||||
|
||||
|
@ -6,6 +6,7 @@ __docformat__ = 'restructuredtext en'
|
||||
|
||||
import os, re, time, sys
|
||||
|
||||
from calibre.ebooks.metadata import title_sort
|
||||
from calibre.ebooks.metadata.book.base import Metadata
|
||||
from calibre.devices.mime import mime_type_ext
|
||||
from calibre.devices.interface import BookList as _BookList
|
||||
@ -54,7 +55,7 @@ class Book(Metadata):
|
||||
def title_sorter(self):
|
||||
doc = '''String to sort the title. If absent, title is returned'''
|
||||
def fget(self):
|
||||
return re.sub('^\s*A\s+|^\s*The\s+|^\s*An\s+', '', self.title).rstrip()
|
||||
return title_sort(self.title)
|
||||
return property(doc=doc, fget=fget)
|
||||
|
||||
@dynamic_property
|
||||
@ -124,7 +125,6 @@ class CollectionsBookList(BookList):
|
||||
collections = {}
|
||||
# This map of sets is used to avoid linear searches when testing for
|
||||
# book equality
|
||||
collections_lpaths = {}
|
||||
for book in self:
|
||||
# Make sure we can identify this book via the lpath
|
||||
lpath = getattr(book, 'lpath', None)
|
||||
@ -198,20 +198,22 @@ class CollectionsBookList(BookList):
|
||||
cat_name = category
|
||||
|
||||
if cat_name not in collections:
|
||||
collections[cat_name] = []
|
||||
collections_lpaths[cat_name] = set()
|
||||
if lpath in collections_lpaths[cat_name]:
|
||||
continue
|
||||
collections_lpaths[cat_name].add(lpath)
|
||||
collections[cat_name] = {}
|
||||
if is_series:
|
||||
collections[cat_name].append(
|
||||
(book, book.get(attr+'_index', sys.maxint)))
|
||||
if doing_dc:
|
||||
collections[cat_name][lpath] = \
|
||||
(book, book.get('series_index', sys.maxint))
|
||||
else:
|
||||
collections[cat_name].append(
|
||||
(book, book.get('title_sort', 'zzzz')))
|
||||
collections[cat_name][lpath] = \
|
||||
(book, book.get(attr+'_index', sys.maxint))
|
||||
else:
|
||||
if lpath not in collections[cat_name]:
|
||||
collections[cat_name][lpath] = \
|
||||
(book, book.get('title_sort', 'zzzz'))
|
||||
# Sort collections
|
||||
result = {}
|
||||
for category, books in collections.items():
|
||||
for category, lpaths in collections.items():
|
||||
books = lpaths.values()
|
||||
books.sort(cmp=lambda x,y:cmp(x[1], y[1]))
|
||||
result[category] = [x[0] for x in books]
|
||||
return result
|
||||
|
@ -94,6 +94,9 @@ class Device(DeviceConfig, DevicePlugin):
|
||||
EBOOK_DIR_CARD_B = ''
|
||||
DELETE_EXTS = []
|
||||
|
||||
# USB disk-based devices can see the book files on the device, so can
|
||||
# copy these back to the library
|
||||
BACKLOADING_ERROR_MESSAGE = None
|
||||
|
||||
def reset(self, key='-1', log_packets=False, report_progress=None,
|
||||
detected_device=None):
|
||||
@ -527,16 +530,8 @@ class Device(DeviceConfig, DevicePlugin):
|
||||
return drives
|
||||
|
||||
def node_mountpoint(self, node):
|
||||
|
||||
def de_mangle(raw):
|
||||
return raw.replace('\\040', ' ').replace('\\011', '\t').replace('\\012',
|
||||
'\n').replace('\\0134', '\\')
|
||||
|
||||
for line in open('/proc/mounts').readlines():
|
||||
line = line.split()
|
||||
if line[0] == node:
|
||||
return de_mangle(line[1])
|
||||
return None
|
||||
from calibre.devices.udisks import node_mountpoint
|
||||
return node_mountpoint(node)
|
||||
|
||||
def find_largest_partition(self, path):
|
||||
node = path.split('/')[-1]
|
||||
@ -582,6 +577,13 @@ class Device(DeviceConfig, DevicePlugin):
|
||||
label += ' (%d)'%extra
|
||||
|
||||
def do_mount(node, label):
|
||||
try:
|
||||
from calibre.devices.udisks import mount
|
||||
mount(node)
|
||||
return 0
|
||||
except:
|
||||
pass
|
||||
|
||||
cmd = 'calibre-mount-helper'
|
||||
if getattr(sys, 'frozen_path', False):
|
||||
cmd = os.path.join(sys.frozen_path, cmd)
|
||||
@ -614,6 +616,7 @@ class Device(DeviceConfig, DevicePlugin):
|
||||
if not mp.endswith('/'): mp += '/'
|
||||
self._linux_mount_map[main] = mp
|
||||
self._main_prefix = mp
|
||||
self._linux_main_device_node = main
|
||||
cards = [(carda, '_card_a_prefix', 'carda'),
|
||||
(cardb, '_card_b_prefix', 'cardb')]
|
||||
for card, prefix, typ in cards:
|
||||
@ -626,6 +629,50 @@ class Device(DeviceConfig, DevicePlugin):
|
||||
setattr(self, prefix, mp)
|
||||
self._linux_mount_map[card] = mp
|
||||
|
||||
self.filter_read_only_mount_points()
|
||||
|
||||
def filter_read_only_mount_points(self):
|
||||
|
||||
def is_readonly(mp):
|
||||
if mp is None:
|
||||
return True
|
||||
path = os.path.join(mp, 'calibre_readonly_test')
|
||||
ro = True
|
||||
try:
|
||||
with open(path, 'wb'):
|
||||
ro = False
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
try:
|
||||
os.remove(path)
|
||||
except:
|
||||
pass
|
||||
return ro
|
||||
|
||||
for mp in ('_main_prefix', '_card_a_prefix', '_card_b_prefix'):
|
||||
if is_readonly(getattr(self, mp, None)):
|
||||
setattr(self, mp, None)
|
||||
|
||||
if self._main_prefix is None:
|
||||
for p in ('_card_a_prefix', '_card_b_prefix'):
|
||||
nmp = getattr(self, p, None)
|
||||
if nmp is not None:
|
||||
self._main_prefix = nmp
|
||||
setattr(self, p, None)
|
||||
break
|
||||
|
||||
if self._main_prefix is None:
|
||||
raise DeviceError(_('The main memory of %s is read only. '
|
||||
'This usually happens because of file system errors.')
|
||||
%self.__class__.__name__)
|
||||
|
||||
if self._card_a_prefix is None and self._card_b_prefix is not None:
|
||||
self._card_a_prefix = self._card_b_prefix
|
||||
self._card_b_prefix = None
|
||||
|
||||
|
||||
|
||||
def open(self):
|
||||
time.sleep(5)
|
||||
self._main_prefix = self._card_a_prefix = self._card_b_prefix = None
|
||||
@ -685,6 +732,11 @@ class Device(DeviceConfig, DevicePlugin):
|
||||
pass
|
||||
|
||||
def eject_linux(self):
|
||||
try:
|
||||
from calibre.devices.udisks import eject
|
||||
return eject(self._linux_main_device_node)
|
||||
except:
|
||||
pass
|
||||
drives = self.find_device_nodes()
|
||||
for drive in drives:
|
||||
if drive:
|
||||
|
@ -93,6 +93,7 @@ class CHMReader(CHMFile):
|
||||
return data
|
||||
|
||||
def ExtractFiles(self, output_dir=os.getcwdu()):
|
||||
html_files = set([])
|
||||
for path in self.Contents():
|
||||
lpath = os.path.join(output_dir, path)
|
||||
self._ensure_dir(lpath)
|
||||
@ -106,14 +107,27 @@ class CHMReader(CHMFile):
|
||||
lpath = lpath.split(';')[0]
|
||||
try:
|
||||
with open(lpath, 'wb') as f:
|
||||
if guess_mimetype(path)[0] == ('text/html'):
|
||||
data = self._reformat(data)
|
||||
f.write(data)
|
||||
try:
|
||||
if 'html' in guess_mimetype(path)[0]:
|
||||
html_files.add(lpath)
|
||||
except:
|
||||
pass
|
||||
except:
|
||||
if iswindows and len(lpath) > 250:
|
||||
self.log.warn('%r filename too long, skipping'%path)
|
||||
continue
|
||||
raise
|
||||
for lpath in html_files:
|
||||
with open(lpath, 'r+b') as f:
|
||||
data = f.read()
|
||||
data = self._reformat(data, lpath)
|
||||
if isinstance(data, unicode):
|
||||
data = data.encode('utf-8')
|
||||
f.seek(0)
|
||||
f.truncate()
|
||||
f.write(data)
|
||||
|
||||
self._extracted = True
|
||||
files = [x for x in os.listdir(output_dir) if
|
||||
os.path.isfile(os.path.join(output_dir, x))]
|
||||
@ -125,7 +139,7 @@ class CHMReader(CHMFile):
|
||||
if self.hhc_path not in files and files:
|
||||
self.hhc_path = files[0]
|
||||
|
||||
def _reformat(self, data):
|
||||
def _reformat(self, data, htmlpath):
|
||||
try:
|
||||
data = xml_to_unicode(data, strip_encoding_pats=True)[0]
|
||||
soup = BeautifulSoup(data)
|
||||
@ -169,15 +183,19 @@ class CHMReader(CHMFile):
|
||||
br[0].extract()
|
||||
|
||||
# some images seem to be broken in some chm's :/
|
||||
for img in soup('img'):
|
||||
try:
|
||||
# some are supposedly "relative"... lies.
|
||||
while img['src'].startswith('../'): img['src'] = img['src'][3:]
|
||||
# some have ";<junk>" at the end.
|
||||
img['src'] = img['src'].split(';')[0]
|
||||
except KeyError:
|
||||
# and some don't even have a src= ?!
|
||||
pass
|
||||
base = os.path.dirname(htmlpath)
|
||||
for img in soup('img', src=True):
|
||||
src = img['src']
|
||||
ipath = os.path.join(base, *src.split('/'))
|
||||
if os.path.exists(ipath):
|
||||
continue
|
||||
src = src.split(';')[0]
|
||||
if not src: continue
|
||||
ipath = os.path.join(base, *src.split('/'))
|
||||
if not os.path.exists(ipath):
|
||||
while src.startswith('../'):
|
||||
src = src[3:]
|
||||
img['src'] = src
|
||||
try:
|
||||
# if there is only a single table with a single element
|
||||
# in the body, replace it by the contents of this single element
|
||||
|
@ -94,7 +94,7 @@ class PageProcessor(list):
|
||||
from calibre.utils.magick import PixelWand
|
||||
for i, wand in enumerate(self.pages):
|
||||
pw = PixelWand()
|
||||
pw.color = 'white'
|
||||
pw.color = '#ffffff'
|
||||
|
||||
wand.set_border_color(pw)
|
||||
if self.rotate:
|
||||
|
@ -838,7 +838,8 @@ OptionRecommendation(name='timestamp',
|
||||
self.opts_to_mi(self.user_metadata)
|
||||
if not hasattr(self.oeb, 'manifest'):
|
||||
self.oeb = create_oebbook(self.log, self.oeb, self.opts,
|
||||
self.input_plugin)
|
||||
self.input_plugin,
|
||||
encoding=self.input_plugin.output_encoding)
|
||||
self.input_plugin.postprocess_book(self.oeb, self.opts, self.log)
|
||||
self.opts.is_image_collection = self.input_plugin.is_image_collection
|
||||
pr = CompositeProgressReporter(0.34, 0.67, self.ui_reporter)
|
||||
|
@ -543,6 +543,13 @@ class HTMLPreProcessor(object):
|
||||
def smarten_punctuation(self, html):
|
||||
from calibre.utils.smartypants import smartyPants
|
||||
from calibre.ebooks.chardet import substitute_entites
|
||||
from uuid import uuid4
|
||||
start = 'calibre-smartypants-'+str(uuid4())
|
||||
stop = 'calibre-smartypants-'+str(uuid4())
|
||||
html = html.replace('<!--', start)
|
||||
html = html.replace('-->', stop)
|
||||
html = smartyPants(html)
|
||||
html = html.replace(start, '<!--')
|
||||
html = html.replace(stop, '-->')
|
||||
return substitute_entites(html)
|
||||
|
||||
|
@ -16,6 +16,7 @@ class EPUBInput(InputFormatPlugin):
|
||||
author = 'Kovid Goyal'
|
||||
description = 'Convert EPUB files (.epub) to HTML'
|
||||
file_types = set(['epub'])
|
||||
output_encoding = None
|
||||
|
||||
recommendations = set([('page_breaks_before', '/', OptionRecommendation.MED)])
|
||||
|
||||
|
@ -45,7 +45,7 @@ def fetch_metadata(url, max=100, timeout=5.):
|
||||
class ISBNDBMetadata(Metadata):
|
||||
|
||||
def __init__(self, book):
|
||||
Metadata.__init__(self, None, [])
|
||||
Metadata.__init__(self, None)
|
||||
|
||||
def tostring(e):
|
||||
if not hasattr(e, 'string'):
|
||||
@ -58,21 +58,21 @@ class ISBNDBMetadata(Metadata):
|
||||
return ans
|
||||
|
||||
self.isbn = unicode(book.get('isbn13', book.get('isbn')))
|
||||
self.title = tostring(book.find('titlelong'))
|
||||
if not self.title:
|
||||
self.title = tostring(book.find('title'))
|
||||
if not self.title:
|
||||
self.title = _('Unknown')
|
||||
title = tostring(book.find('titlelong'))
|
||||
if not title:
|
||||
title = tostring(book.find('title'))
|
||||
self.title = title
|
||||
self.title = unicode(self.title).strip()
|
||||
self.authors = []
|
||||
authors = []
|
||||
au = tostring(book.find('authorstext'))
|
||||
if au:
|
||||
au = au.strip()
|
||||
temp = au.split(',')
|
||||
for au in temp:
|
||||
if not au: continue
|
||||
self.authors.extend([a.strip() for a in au.split('&')])
|
||||
|
||||
authors.extend([a.strip() for a in au.split('&')])
|
||||
if authors:
|
||||
self.authors = authors
|
||||
try:
|
||||
self.author_sort = tostring(book.find('authors').find('person'))
|
||||
if self.authors and self.author_sort == self.authors[0]:
|
||||
|
@ -5,7 +5,7 @@ from __future__ import with_statement
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Li Fanxi <lifanxi@freemindworld.com>'
|
||||
|
||||
import re, os
|
||||
import os
|
||||
from StringIO import StringIO
|
||||
from calibre.ebooks.metadata import MetaInformation
|
||||
from calibre.ebooks.snb.snbfile import SNBFile
|
||||
@ -40,8 +40,8 @@ def get_metadata(stream, extract_cover=True):
|
||||
ext = '.jpg'
|
||||
mi.cover_data = (ext[-3:], snbFile.GetFileStream('snbc/images/' + cover.text))
|
||||
|
||||
except Exception, e:
|
||||
print e
|
||||
pass
|
||||
except Exception:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
return mi
|
||||
|
@ -2,7 +2,7 @@
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
|
||||
import os, glob, re
|
||||
import os, glob, re, functools
|
||||
from urlparse import urlparse
|
||||
from urllib import unquote
|
||||
from uuid import uuid4
|
||||
@ -11,7 +11,7 @@ from lxml import etree
|
||||
from lxml.builder import ElementMaker
|
||||
|
||||
from calibre.constants import __appname__, __version__
|
||||
from calibre.ebooks.BeautifulSoup import BeautifulStoneSoup, BeautifulSoup
|
||||
from calibre.ebooks.BeautifulSoup import BeautifulSoup
|
||||
from calibre.ebooks.chardet import xml_to_unicode
|
||||
|
||||
NCX_NS = "http://www.daisy.org/z3986/2005/ncx/"
|
||||
@ -26,14 +26,6 @@ E = ElementMaker(namespace=NCX_NS, nsmap=NSMAP)
|
||||
|
||||
C = ElementMaker(namespace=CALIBRE_NS, nsmap=NSMAP)
|
||||
|
||||
class NCXSoup(BeautifulStoneSoup):
|
||||
|
||||
NESTABLE_TAGS = {'navpoint':[]}
|
||||
|
||||
def __init__(self, raw):
|
||||
BeautifulStoneSoup.__init__(self, raw,
|
||||
convertEntities=BeautifulSoup.HTML_ENTITIES,
|
||||
selfClosingTags=['meta', 'content'])
|
||||
|
||||
class TOC(list):
|
||||
|
||||
@ -166,40 +158,60 @@ class TOC(list):
|
||||
|
||||
def read_ncx_toc(self, toc):
|
||||
self.base_path = os.path.dirname(toc)
|
||||
raw = xml_to_unicode(open(toc, 'rb').read(), assume_utf8=True)[0]
|
||||
soup = NCXSoup(raw)
|
||||
raw = xml_to_unicode(open(toc, 'rb').read(), assume_utf8=True,
|
||||
strip_encoding_pats=True)[0]
|
||||
root = etree.fromstring(raw, parser=etree.XMLParser(recover=True,
|
||||
no_network=True))
|
||||
xpn = {'re': 'http://exslt.org/regular-expressions'}
|
||||
XPath = functools.partial(etree.XPath, namespaces=xpn)
|
||||
|
||||
def get_attr(node, default=None, attr='playorder'):
|
||||
for name, val in node.attrib.items():
|
||||
if name and val and name.lower().endswith(attr):
|
||||
return val
|
||||
return default
|
||||
|
||||
nl_path = XPath('./*[re:match(local-name(), "navlabel$", "i")]')
|
||||
txt_path = XPath('./*[re:match(local-name(), "text$", "i")]')
|
||||
content_path = XPath('./*[re:match(local-name(), "content$", "i")]')
|
||||
np_path = XPath('./*[re:match(local-name(), "navpoint$", "i")]')
|
||||
|
||||
def process_navpoint(np, dest):
|
||||
play_order = np.get('playOrder', None)
|
||||
if play_order is None:
|
||||
play_order = int(np.get('playorder', 1))
|
||||
try:
|
||||
play_order = int(get_attr(np, 1))
|
||||
except:
|
||||
play_order = 1
|
||||
href = fragment = text = None
|
||||
nl = np.find(re.compile('navlabel'))
|
||||
if nl is not None:
|
||||
nl = nl_path(np)
|
||||
if nl:
|
||||
nl = nl[0]
|
||||
text = u''
|
||||
for txt in nl.findAll(re.compile('text')):
|
||||
text += u''.join([unicode(s) for s in txt.findAll(text=True)])
|
||||
content = np.find(re.compile('content'))
|
||||
if content is None or not content.has_key('src') or not txt:
|
||||
for txt in txt_path(nl):
|
||||
text += etree.tostring(txt, method='text',
|
||||
encoding=unicode, with_tail=False)
|
||||
content = content_path(np)
|
||||
if not content or not text:
|
||||
return
|
||||
content = content[0]
|
||||
src = get_attr(content, attr='src')
|
||||
if src is None:
|
||||
return
|
||||
|
||||
purl = urlparse(unquote(content['src']))
|
||||
purl = urlparse(unquote(content.get('src')))
|
||||
href, fragment = purl[2], purl[5]
|
||||
nd = dest.add_item(href, fragment, text)
|
||||
nd.play_order = play_order
|
||||
|
||||
for c in np:
|
||||
if 'navpoint' in getattr(c, 'name', ''):
|
||||
for c in np_path(np):
|
||||
process_navpoint(c, nd)
|
||||
|
||||
nm = soup.find(re.compile('navmap'))
|
||||
if nm is None:
|
||||
nm = XPath('//*[re:match(local-name(), "navmap$", "i")]')(root)
|
||||
if not nm:
|
||||
raise ValueError('NCX files must have a <navmap> element.')
|
||||
nm = nm[0]
|
||||
|
||||
for elem in nm:
|
||||
if 'navpoint' in getattr(elem, 'name', ''):
|
||||
process_navpoint(elem, self)
|
||||
|
||||
for child in np_path(nm):
|
||||
process_navpoint(child, self)
|
||||
|
||||
def read_html_toc(self, toc):
|
||||
self.base_path = os.path.dirname(toc)
|
||||
|
@ -282,9 +282,9 @@ def XPath(expr):
|
||||
def xpath(elem, expr):
|
||||
return elem.xpath(expr, namespaces=XPNSMAP)
|
||||
|
||||
def xml2str(root, pretty_print=False, strip_comments=False):
|
||||
def xml2str(root, pretty_print=False, strip_comments=False, with_tail=True):
|
||||
ans = etree.tostring(root, encoding='utf-8', xml_declaration=True,
|
||||
pretty_print=pretty_print)
|
||||
pretty_print=pretty_print, with_tail=with_tail)
|
||||
|
||||
if strip_comments:
|
||||
ans = re.compile(r'<!--.*?-->', re.DOTALL).sub('', ans)
|
||||
@ -1908,6 +1908,7 @@ class OEBBook(object):
|
||||
|
||||
def _to_ncx(self):
|
||||
lang = unicode(self.metadata.language[0])
|
||||
lang = lang.replace('_', '-')
|
||||
ncx = etree.Element(NCX('ncx'),
|
||||
attrib={'version': '2005-1', XML('lang'): lang},
|
||||
nsmap={None: NCX_NS})
|
||||
|
@ -55,7 +55,7 @@ class SVGRasterizer(object):
|
||||
self.rasterize_cover()
|
||||
|
||||
def rasterize_svg(self, elem, width=0, height=0, format='PNG'):
|
||||
data = QByteArray(xml2str(elem))
|
||||
data = QByteArray(xml2str(elem, with_tail=False))
|
||||
svg = QSvgRenderer(data)
|
||||
size = svg.defaultSize()
|
||||
view_box = elem.get('viewBox', elem.get('viewbox', None))
|
||||
|
@ -6,12 +6,11 @@ __docformat__ = 'restructuredtext en'
|
||||
|
||||
import os, uuid
|
||||
|
||||
from calibre.customize.conversion import InputFormatPlugin, OptionRecommendation
|
||||
from calibre.customize.conversion import InputFormatPlugin
|
||||
from calibre.ebooks.oeb.base import DirContainer
|
||||
from calibre.ebooks.snb.snbfile import SNBFile
|
||||
from calibre.ptempfile import TemporaryDirectory
|
||||
from calibre.utils.filenames import ascii_filename
|
||||
from calibre import prepare_string_for_xml
|
||||
from lxml import etree
|
||||
|
||||
HTML_TEMPLATE = u'<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><title>%s</title></head><body>\n%s\n</body></html>'
|
||||
|
@ -10,7 +10,6 @@ from lxml import etree
|
||||
from calibre.customize.conversion import OutputFormatPlugin, OptionRecommendation
|
||||
from calibre.ptempfile import TemporaryDirectory
|
||||
from calibre.constants import __appname__, __version__
|
||||
from calibre.ebooks.oeb.base import XHTML, XHTML_NS, barename, namespace
|
||||
from calibre.ebooks.snb.snbfile import SNBFile
|
||||
from calibre.ebooks.snb.snbml import SNBMLizer, ProcessFileName
|
||||
|
||||
@ -28,15 +27,14 @@ class SNBOutput(OutputFormatPlugin):
|
||||
# 'Use \'old_mac\' for compatibility with Mac OS 9 and earlier. '
|
||||
# 'For Mac OS X use \'unix\'. \'system\' will default to the newline '
|
||||
# 'type used by this OS.') % sorted(TxtNewlines.NEWLINE_TYPES.keys())),
|
||||
OptionRecommendation(name='output_encoding', recommended_value='utf-8',
|
||||
OptionRecommendation(name='snb_output_encoding', recommended_value='utf-8',
|
||||
level=OptionRecommendation.LOW,
|
||||
help=_('Specify the character encoding of the output document. ' \
|
||||
'The default is utf-8. Note: This option is not honored by all ' \
|
||||
'formats.')),
|
||||
'The default is utf-8.')),
|
||||
# OptionRecommendation(name='inline_toc',
|
||||
# recommended_value=False, level=OptionRecommendation.LOW,
|
||||
# help=_('Add Table of Contents to beginning of the book.')),
|
||||
OptionRecommendation(name='max_line_length',
|
||||
OptionRecommendation(name='snb_max_line_length',
|
||||
recommended_value=0, level=OptionRecommendation.LOW,
|
||||
help=_('The maximum number of characters per line. This splits on '
|
||||
'the first space before the specified value. If no space is found '
|
||||
@ -51,6 +49,13 @@ class SNBOutput(OutputFormatPlugin):
|
||||
|
||||
def convert(self, oeb_book, output_path, input_plugin, opts, log):
|
||||
self.opts = opts
|
||||
from calibre.ebooks.oeb.transforms.rasterize import SVGRasterizer, Unavailable
|
||||
try:
|
||||
rasterizer = SVGRasterizer()
|
||||
rasterizer(oeb_book, opts)
|
||||
except Unavailable:
|
||||
log.warn('SVG rasterizer unavailable, SVG will not be converted')
|
||||
|
||||
# Create temp dir
|
||||
with TemporaryDirectory('_snb_output') as tdir:
|
||||
# Create stub directories
|
||||
@ -82,7 +87,6 @@ class SNBOutput(OutputFormatPlugin):
|
||||
abstract = ''
|
||||
|
||||
# Process Cover
|
||||
from calibre.ebooks.oeb.base import urldefrag
|
||||
g, m, s = oeb_book.guide, oeb_book.manifest, oeb_book.spine
|
||||
href = None
|
||||
if 'titlepage' not in g:
|
||||
@ -227,14 +231,11 @@ class SNBOutput(OutputFormatPlugin):
|
||||
(x,y) = img.size
|
||||
if self.opts:
|
||||
SCREEN_Y, SCREEN_X = self.opts.output_profile.comic_screen_size
|
||||
print SCREEN_Y, SCREEN_X
|
||||
else:
|
||||
SCREEN_X = 540
|
||||
SCREEN_Y = 700
|
||||
# Handle big image only
|
||||
if x > SCREEN_X or y > SCREEN_Y:
|
||||
SCREEN_RATIO = float(SCREEN_Y) / SCREEN_X
|
||||
imgRatio = float(y) / x
|
||||
xScale = float(x) / SCREEN_X
|
||||
yScale = float(y) / SCREEN_Y
|
||||
scale = max(xScale, yScale)
|
||||
|
@ -4,7 +4,7 @@ __license__ = 'GPL 3'
|
||||
__copyright__ = '2010, Li Fanxi <lifanxi@freemindworld.com>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import sys, struct, zlib, bz2, os, math
|
||||
import sys, struct, zlib, bz2, os
|
||||
from mimetypes import types_map
|
||||
|
||||
class FileStream:
|
||||
@ -222,7 +222,7 @@ class SNBFile:
|
||||
plainBlockOffset = binBlockOffset + len(binStream)
|
||||
|
||||
binBlock = (len(binStream) + 0x8000 - 1) / 0x8000
|
||||
plainBlock = (len(plainStream) + 0x8000 - 1) / 0x8000
|
||||
#plainBlock = (len(plainStream) + 0x8000 - 1) / 0x8000
|
||||
|
||||
offset = 0
|
||||
tailBlock = ''
|
||||
|
@ -157,9 +157,9 @@ class SNBMLizer(object):
|
||||
text = re.sub('(?imu)^[ ]+', '', text)
|
||||
text = re.sub('(?imu)[ ]+$', '', text)
|
||||
|
||||
if self.opts.max_line_length:
|
||||
max_length = self.opts.max_line_length
|
||||
if self.opts.max_line_length < 25 and not self.opts.force_max_line_length:
|
||||
if self.opts.snb_max_line_length:
|
||||
max_length = self.opts.snb_max_line_length
|
||||
if self.opts.max_line_length < 25:# and not self.opts.force_max_line_length:
|
||||
max_length = 25
|
||||
short_lines = []
|
||||
lines = text.splitlines()
|
||||
@ -172,7 +172,7 @@ class SNBMLizer(object):
|
||||
line = line[space + 1:]
|
||||
else:
|
||||
# Space was not found.
|
||||
if self.opts.force_max_line_length:
|
||||
if False and self.opts.force_max_line_length:
|
||||
# Force breaking at max_lenght.
|
||||
short_lines.append(line[:max_length])
|
||||
line = line[max_length:]
|
||||
@ -247,7 +247,7 @@ class SNBMLizer(object):
|
||||
en = u''
|
||||
if len(text) >= 2:
|
||||
en = text[-1][-2:]
|
||||
t, li = self.dump_text(subitems, item, stylizer, en, pre, li)
|
||||
t = self.dump_text(subitems, item, stylizer, en, pre, li)[0]
|
||||
text += t
|
||||
|
||||
if in_block:
|
||||
|
@ -236,6 +236,10 @@ class AddAction(InterfaceAction):
|
||||
self.gui.refresh_ondevice()
|
||||
|
||||
def add_books_from_device(self, view, paths=None):
|
||||
backloading_err = self.gui.device_manager.device.BACKLOADING_ERROR_MESSAGE
|
||||
if backloading_err is not None:
|
||||
return error_dialog(self.gui, _('Add to library'), backloading_err,
|
||||
show=True)
|
||||
if paths is None:
|
||||
rows = view.selectionModel().selectedRows()
|
||||
if not rows or len(rows) == 0:
|
||||
|
@ -169,7 +169,7 @@ class EditMetadataAction(InterfaceAction):
|
||||
self.gui.tags_view.blockSignals(False)
|
||||
if changed:
|
||||
m = self.gui.library_view.model()
|
||||
m.resort(reset=False)
|
||||
m.refresh(reset=False)
|
||||
m.research()
|
||||
self.gui.tags_view.recount()
|
||||
if self.gui.cover_flow:
|
||||
|
@ -172,7 +172,7 @@ class MetadataWidget(Widget, Ui_Form):
|
||||
if _file:
|
||||
_file = os.path.abspath(_file)
|
||||
if not os.access(_file, os.R_OK):
|
||||
d = error_dialog(self.window, _('Cannot read'),
|
||||
d = error_dialog(self.parent(), _('Cannot read'),
|
||||
_('You do not have permission to read the file: ') + _file)
|
||||
d.exec_()
|
||||
return
|
||||
@ -181,14 +181,14 @@ class MetadataWidget(Widget, Ui_Form):
|
||||
cf = open(_file, "rb")
|
||||
cover = cf.read()
|
||||
except IOError, e:
|
||||
d = error_dialog(self.window, _('Error reading file'),
|
||||
d = error_dialog(self.parent(), _('Error reading file'),
|
||||
_("<p>There was an error reading from file: <br /><b>") + _file + "</b></p><br />"+str(e))
|
||||
d.exec_()
|
||||
if cover:
|
||||
pix = QPixmap()
|
||||
pix.loadFromData(cover)
|
||||
if pix.isNull():
|
||||
d = error_dialog(self.window, _('Error reading file'),
|
||||
d = error_dialog(self.parent(), _('Error reading file'),
|
||||
_file + _(" is not a valid picture"))
|
||||
d.exec_()
|
||||
else:
|
||||
|
@ -6,7 +6,6 @@ __docformat__ = 'restructuredtext en'
|
||||
|
||||
from calibre.gui2.convert.snb_output_ui import Ui_Form
|
||||
from calibre.gui2.convert import Widget
|
||||
from calibre.gui2.widgets import BasicComboModel
|
||||
|
||||
newline_model = None
|
||||
|
||||
|
@ -793,11 +793,17 @@ class DeviceMixin(object): # {{{
|
||||
self.set_books_in_library(job.result, reset=True)
|
||||
mainlist, cardalist, cardblist = job.result
|
||||
self.memory_view.set_database(mainlist)
|
||||
self.memory_view.set_editable(self.device_manager.device.CAN_SET_METADATA)
|
||||
self.memory_view.set_editable(self.device_manager.device.CAN_SET_METADATA,
|
||||
self.device_manager.device.BACKLOADING_ERROR_MESSAGE
|
||||
is None)
|
||||
self.card_a_view.set_database(cardalist)
|
||||
self.card_a_view.set_editable(self.device_manager.device.CAN_SET_METADATA)
|
||||
self.card_a_view.set_editable(self.device_manager.device.CAN_SET_METADATA,
|
||||
self.device_manager.device.BACKLOADING_ERROR_MESSAGE
|
||||
is None)
|
||||
self.card_b_view.set_database(cardblist)
|
||||
self.card_b_view.set_editable(self.device_manager.device.CAN_SET_METADATA)
|
||||
self.card_b_view.set_editable(self.device_manager.device.CAN_SET_METADATA,
|
||||
self.device_manager.device.BACKLOADING_ERROR_MESSAGE
|
||||
is None)
|
||||
self.sync_news()
|
||||
self.sync_catalogs()
|
||||
self.refresh_ondevice()
|
||||
|
@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>752</width>
|
||||
<height>715</height>
|
||||
<height>633</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@ -263,7 +263,7 @@
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>00</height>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
@ -357,13 +357,13 @@ from the value in the box</string>
|
||||
</item>
|
||||
<item row="12" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="change_title_to_title_case">
|
||||
<property name="text">
|
||||
<string>Change title to title case</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Force the title to be in title case. If both this and swap authors are checked,
|
||||
title and author are swapped before the title case is set</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Change title to title case</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="0" colspan="2">
|
||||
@ -486,15 +486,15 @@ Future conversion of these books will use the default settings.</string>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="HistoryLineEdit" name="search_for">
|
||||
<property name="toolTip">
|
||||
<string>Enter the what you are looking for, either plain text or a regular expression, depending on the mode</string>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>100</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Enter the what you are looking for, either plain text or a regular expression, depending on the mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
@ -656,6 +656,14 @@ nothing should be put between the original text and the inserted text</string>
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="gridLayoutWidget_2">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>726</width>
|
||||
<height>334</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="testgrid">
|
||||
<item row="8" column="0">
|
||||
<widget class="QLabel" name="label_31">
|
||||
@ -674,19 +682,6 @@ nothing should be put between the original text and the inserted text</string>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="20" column="1">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
@ -733,14 +728,33 @@ nothing should be put between the original text and the inserted text</string>
|
||||
<tabstop>author_sort</tabstop>
|
||||
<tabstop>rating</tabstop>
|
||||
<tabstop>publisher</tabstop>
|
||||
<tabstop>tag_editor_button</tabstop>
|
||||
<tabstop>tags</tabstop>
|
||||
<tabstop>tag_editor_button</tabstop>
|
||||
<tabstop>remove_tags</tabstop>
|
||||
<tabstop>remove_all_tags</tabstop>
|
||||
<tabstop>series</tabstop>
|
||||
<tabstop>clear_series</tabstop>
|
||||
<tabstop>autonumber_series</tabstop>
|
||||
<tabstop>series_numbering_restarts</tabstop>
|
||||
<tabstop>series_start_number</tabstop>
|
||||
<tabstop>remove_format</tabstop>
|
||||
<tabstop>remove_conversion_settings</tabstop>
|
||||
<tabstop>swap_title_and_author</tabstop>
|
||||
<tabstop>change_title_to_title_case</tabstop>
|
||||
<tabstop>button_box</tabstop>
|
||||
<tabstop>central_widget</tabstop>
|
||||
<tabstop>search_field</tabstop>
|
||||
<tabstop>search_mode</tabstop>
|
||||
<tabstop>search_for</tabstop>
|
||||
<tabstop>case_sensitive</tabstop>
|
||||
<tabstop>replace_with</tabstop>
|
||||
<tabstop>replace_func</tabstop>
|
||||
<tabstop>destination_field</tabstop>
|
||||
<tabstop>replace_mode</tabstop>
|
||||
<tabstop>comma_separated</tabstop>
|
||||
<tabstop>scrollArea11</tabstop>
|
||||
<tabstop>test_text</tabstop>
|
||||
<tabstop>test_result</tabstop>
|
||||
</tabstops>
|
||||
<resources>
|
||||
<include location="../../../../resources/images.qrc"/>
|
||||
|
@ -434,9 +434,9 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
|
||||
self.pubdate.setDate(QDate(pubdate.year, pubdate.month,
|
||||
pubdate.day))
|
||||
timestamp = db.timestamp(self.id, index_is_id=True)
|
||||
self.orig_timestamp = timestamp
|
||||
self.date.setDate(QDate(timestamp.year, timestamp.month,
|
||||
timestamp.day))
|
||||
self.orig_date = qt_to_dt(self.date.date())
|
||||
|
||||
exts = self.db.formats(row)
|
||||
if exts:
|
||||
@ -729,10 +729,13 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
|
||||
self.series.setText(book.series)
|
||||
if book.series_index is not None:
|
||||
self.series_index.setValue(book.series_index)
|
||||
# Needed because of Qt focus bug on OS X
|
||||
self.fetch_cover_button.setFocus(Qt.OtherFocusReason)
|
||||
else:
|
||||
error_dialog(self, _('Cannot fetch metadata'),
|
||||
_('You must specify at least one of ISBN, Title, '
|
||||
'Authors or Publisher'), show=True)
|
||||
self.title.setFocus(Qt.OtherFocusReason)
|
||||
|
||||
def enable_series_index(self, *args):
|
||||
self.series_index.setEnabled(True)
|
||||
@ -802,7 +805,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
|
||||
self.db.set_pubdate(self.id, d, notify=False, commit=False)
|
||||
d = self.date.date()
|
||||
d = qt_to_dt(d)
|
||||
if d.date() != self.orig_timestamp.date():
|
||||
if d != self.orig_date:
|
||||
self.db.set_timestamp(self.id, d, notify=False, commit=False)
|
||||
self.db.commit()
|
||||
|
||||
|
@ -120,12 +120,15 @@ class SchedulerDialog(QDialog, Ui_Dialog):
|
||||
|
||||
if self.account.isVisible():
|
||||
un, pw = map(unicode, (self.username.text(), self.password.text()))
|
||||
un, pw = un.strip(), pw.strip()
|
||||
if not un and not pw and self.schedule.isChecked():
|
||||
if not getattr(self, 'subscription_optional', False):
|
||||
error_dialog(self, _('Need username and password'),
|
||||
_('You must provide a username and/or password to '
|
||||
'use this news source.'), show=True)
|
||||
return False
|
||||
self.recipe_model.set_account_info(urn, un.strip(), pw.strip())
|
||||
if un or pw:
|
||||
self.recipe_model.set_account_info(urn, un, pw)
|
||||
|
||||
if self.schedule.isChecked():
|
||||
schedule_type = 'interval' if self.interval_button.isChecked() else 'day/time'
|
||||
@ -157,7 +160,13 @@ class SchedulerDialog(QDialog, Ui_Dialog):
|
||||
account_info = self.recipe_model.account_info_from_urn(urn)
|
||||
customize_info = self.recipe_model.get_customize_info(urn)
|
||||
|
||||
self.account.setVisible(recipe.get('needs_subscription', '') == 'yes')
|
||||
ns = recipe.get('needs_subscription', '')
|
||||
self.account.setVisible(ns in ('yes', 'optional'))
|
||||
self.subscription_optional = ns == 'optional'
|
||||
act = _('Account')
|
||||
act2 = _('(optional)') if self.subscription_optional else \
|
||||
_('(required)')
|
||||
self.account.setTitle(act+' '+act2)
|
||||
un = pw = ''
|
||||
if account_info is not None:
|
||||
un, pw = account_info[:2]
|
||||
|
@ -30,6 +30,7 @@ class BooksView(QTableView): # {{{
|
||||
def __init__(self, parent, modelcls=BooksModel):
|
||||
QTableView.__init__(self, parent)
|
||||
|
||||
self.drag_allowed = True
|
||||
self.setDragEnabled(True)
|
||||
self.setDragDropOverwriteMode(False)
|
||||
self.setDragDropMode(self.DragDrop)
|
||||
@ -505,6 +506,8 @@ class BooksView(QTableView): # {{{
|
||||
return QTableView.mousePressEvent(self, event)
|
||||
|
||||
def mouseMoveEvent(self, event):
|
||||
if not self.drag_allowed:
|
||||
return
|
||||
if self.drag_start_pos is None:
|
||||
return QTableView.mouseMoveEvent(self, event)
|
||||
|
||||
@ -613,7 +616,7 @@ class BooksView(QTableView): # {{{
|
||||
def close(self):
|
||||
self._model.close()
|
||||
|
||||
def set_editable(self, editable):
|
||||
def set_editable(self, editable, supports_backloading):
|
||||
self._model.set_editable(editable)
|
||||
|
||||
def connect_to_search_box(self, sb, search_done):
|
||||
@ -700,5 +703,9 @@ class DeviceBooksView(BooksView): # {{{
|
||||
error_dialog(self, _('Not allowed'),
|
||||
_('Dropping onto a device is not supported. First add the book to the calibre library.')).exec_()
|
||||
|
||||
def set_editable(self, editable, supports_backloading):
|
||||
self._model.set_editable(editable)
|
||||
self.drag_allowed = supports_backloading
|
||||
|
||||
# }}}
|
||||
|
||||
|
@ -73,6 +73,8 @@ class SearchBox2(QComboBox):
|
||||
self.normal_background = 'rgb(255, 255, 255, 0%)'
|
||||
self.line_edit = SearchLineEdit(self)
|
||||
self.setLineEdit(self.line_edit)
|
||||
c = self.line_edit.completer()
|
||||
c.setCompletionMode(c.PopupCompletion)
|
||||
self.line_edit.key_pressed.connect(self.key_pressed,
|
||||
type=Qt.DirectConnection)
|
||||
self.line_edit.mouse_released.connect(self.mouse_released,
|
||||
|
@ -17,7 +17,7 @@ from PyQt4.Qt import Qt, QTreeView, QApplication, pyqtSignal, \
|
||||
|
||||
from calibre.ebooks.metadata import title_sort
|
||||
from calibre.gui2 import config, NONE
|
||||
from calibre.library.field_metadata import TagsIcons
|
||||
from calibre.library.field_metadata import TagsIcons, category_icon_map
|
||||
from calibre.utils.search_query_parser import saved_searches
|
||||
from calibre.gui2 import error_dialog
|
||||
from calibre.gui2.dialogs.confirm_delete import confirm
|
||||
@ -84,12 +84,14 @@ class TagsView(QTreeView): # {{{
|
||||
self.setAcceptDrops(True)
|
||||
self.setDragDropMode(self.DropOnly)
|
||||
self.setDropIndicatorShown(True)
|
||||
self.setAutoExpandDelay(500)
|
||||
|
||||
def set_database(self, db, tag_match, sort_by):
|
||||
self.hidden_categories = config['tag_browser_hidden_categories']
|
||||
self._model = TagsModel(db, parent=self,
|
||||
hidden_categories=self.hidden_categories,
|
||||
search_restriction=None)
|
||||
search_restriction=None,
|
||||
drag_drop_finished=self.drag_drop_finished)
|
||||
self.sort_by = sort_by
|
||||
self.tag_match = tag_match
|
||||
self.db = db
|
||||
@ -109,103 +111,6 @@ class TagsView(QTreeView): # {{{
|
||||
def database_changed(self, event, ids):
|
||||
self.refresh_required.emit()
|
||||
|
||||
def dragEnterEvent(self, event):
|
||||
md = event.mimeData()
|
||||
if md.hasFormat("application/calibre+from_library"):
|
||||
event.setDropAction(Qt.CopyAction)
|
||||
event.accept()
|
||||
else:
|
||||
event.ignore()
|
||||
|
||||
def dragMoveEvent(self, event):
|
||||
allowed = False
|
||||
idx = self.indexAt(event.pos())
|
||||
m = self.model()
|
||||
p = m.parent(idx)
|
||||
if idx.isValid() and p.isValid():
|
||||
item = m.data(p, Qt.UserRole)
|
||||
fm = self.db.metadata_for_field(item.category_key)
|
||||
if item.category_key in \
|
||||
('tags', 'series', 'authors', 'rating', 'publisher') or\
|
||||
(fm['is_custom'] and \
|
||||
fm['datatype'] in ['text', 'rating', 'series']):
|
||||
allowed = True
|
||||
if allowed:
|
||||
event.acceptProposedAction()
|
||||
else:
|
||||
event.ignore()
|
||||
|
||||
def dropEvent(self, event):
|
||||
idx = self.indexAt(event.pos())
|
||||
m = self.model()
|
||||
p = m.parent(idx)
|
||||
if idx.isValid() and p.isValid():
|
||||
item = m.data(p, Qt.UserRole)
|
||||
if item.type == TagTreeItem.CATEGORY:
|
||||
fm = self.db.metadata_for_field(item.category_key)
|
||||
if item.category_key in \
|
||||
('tags', 'series', 'authors', 'rating', 'publisher') or\
|
||||
(fm['is_custom'] and \
|
||||
fm['datatype'] in ['text', 'rating', 'series']):
|
||||
child = m.data(idx, Qt.UserRole)
|
||||
md = event.mimeData()
|
||||
mime = 'application/calibre+from_library'
|
||||
ids = list(map(int, str(md.data(mime)).split()))
|
||||
self.handle_drop(item, child, ids)
|
||||
event.accept()
|
||||
return
|
||||
event.ignore()
|
||||
|
||||
def handle_drop(self, parent, child, ids):
|
||||
# print 'Dropped ids:', ids, parent.category_key, child.tag.name
|
||||
key = parent.category_key
|
||||
if (key == 'authors' and len(ids) >= 5):
|
||||
if not confirm('<p>'+_('Changing the authors for several books can '
|
||||
'take a while. Are you sure?')
|
||||
+'</p>', 'tag_browser_drop_authors', self):
|
||||
return
|
||||
elif len(ids) > 15:
|
||||
if not confirm('<p>'+_('Changing the metadata for that many books '
|
||||
'can take a while. Are you sure?')
|
||||
+'</p>', 'tag_browser_many_changes', self):
|
||||
return
|
||||
|
||||
fm = self.db.metadata_for_field(key)
|
||||
is_multiple = fm['is_multiple']
|
||||
val = child.tag.name
|
||||
for id in ids:
|
||||
mi = self.db.get_metadata(id, index_is_id=True)
|
||||
|
||||
# Prepare to ignore the author, unless it is changed. Title is
|
||||
# always ignored -- see the call to set_metadata
|
||||
set_authors = False
|
||||
|
||||
# Author_sort cannot change explicitly. Changing the author might
|
||||
# change it.
|
||||
mi.author_sort = None # Never will change by itself.
|
||||
|
||||
if key == 'authors':
|
||||
mi.authors = [val]
|
||||
set_authors=True
|
||||
elif fm['datatype'] == 'rating':
|
||||
mi.set(key, len(val) * 2)
|
||||
elif fm['is_custom'] and fm['datatype'] == 'series':
|
||||
mi.set(key, val, extra=1.0)
|
||||
elif is_multiple:
|
||||
new_val = mi.get(key, [])
|
||||
if val in new_val:
|
||||
# Fortunately, only one field can change, so the continue
|
||||
# won't break anything
|
||||
continue
|
||||
new_val.append(val)
|
||||
mi.set(key, new_val)
|
||||
else:
|
||||
mi.set(key, val)
|
||||
self.db.set_metadata(id, mi, set_title=False,
|
||||
set_authors=set_authors, commit=False)
|
||||
self.db.commit()
|
||||
self.drag_drop_finished.emit(ids)
|
||||
|
||||
@property
|
||||
def match_all(self):
|
||||
return self.tag_match and self.tag_match.currentIndex() > 0
|
||||
@ -374,7 +279,8 @@ class TagsView(QTreeView): # {{{
|
||||
try:
|
||||
self._model = TagsModel(self.db, parent=self,
|
||||
hidden_categories=self.hidden_categories,
|
||||
search_restriction=self.search_restriction)
|
||||
search_restriction=self.search_restriction,
|
||||
drag_drop_finished=self.drag_drop_finished)
|
||||
self.setModel(self._model)
|
||||
except:
|
||||
# The DB must be gone. Set the model to None and hope that someone
|
||||
@ -469,24 +375,20 @@ class TagTreeItem(object): # {{{
|
||||
|
||||
class TagsModel(QAbstractItemModel): # {{{
|
||||
|
||||
def __init__(self, db, parent, hidden_categories=None, search_restriction=None):
|
||||
def __init__(self, db, parent, hidden_categories=None,
|
||||
search_restriction=None, drag_drop_finished=None):
|
||||
QAbstractItemModel.__init__(self, parent)
|
||||
|
||||
# must do this here because 'QPixmap: Must construct a QApplication
|
||||
# before a QPaintDevice'. The ':' in front avoids polluting either the
|
||||
# user-defined categories (':' at end) or columns namespaces (no ':').
|
||||
self.category_icon_map = TagsIcons({
|
||||
'authors' : QIcon(I('user_profile.png')),
|
||||
'series' : QIcon(I('series.png')),
|
||||
'formats' : QIcon(I('book.png')),
|
||||
'publisher' : QIcon(I('publisher.png')),
|
||||
'rating' : QIcon(I('rating.png')),
|
||||
'news' : QIcon(I('news.png')),
|
||||
'tags' : QIcon(I('tags.png')),
|
||||
':custom' : QIcon(I('column.png')),
|
||||
':user' : QIcon(I('drawer.png')),
|
||||
'search' : QIcon(I('search.png'))})
|
||||
iconmap = {}
|
||||
for key in category_icon_map:
|
||||
iconmap[key] = QIcon(I(category_icon_map[key]))
|
||||
self.category_icon_map = TagsIcons(iconmap)
|
||||
|
||||
self.categories_with_ratings = ['authors', 'series', 'publisher', 'tags']
|
||||
self.drag_drop_finished = drag_drop_finished
|
||||
|
||||
self.icon_state_map = [None, QIcon(I('plus.png')), QIcon(I('minus.png'))]
|
||||
self.db = db
|
||||
@ -519,6 +421,79 @@ class TagsModel(QAbstractItemModel): # {{{
|
||||
tag.avg_rating = None
|
||||
TagTreeItem(parent=c, data=tag, icon_map=self.icon_state_map)
|
||||
|
||||
def mimeTypes(self):
|
||||
return ["application/calibre+from_library"]
|
||||
|
||||
def dropMimeData(self, md, action, row, column, parent):
|
||||
if not md.hasFormat("application/calibre+from_library") or \
|
||||
action != Qt.CopyAction:
|
||||
return False
|
||||
idx = parent
|
||||
if idx.isValid():
|
||||
node = self.data(idx, Qt.UserRole)
|
||||
if node.type == TagTreeItem.TAG:
|
||||
fm = self.db.metadata_for_field(node.tag.category)
|
||||
if node.tag.category in \
|
||||
('tags', 'series', 'authors', 'rating', 'publisher') or \
|
||||
(fm['is_custom'] and \
|
||||
fm['datatype'] in ['text', 'rating', 'series']):
|
||||
mime = 'application/calibre+from_library'
|
||||
ids = list(map(int, str(md.data(mime)).split()))
|
||||
self.handle_drop(node, ids)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def handle_drop(self, on_node, ids):
|
||||
#print 'Dropped ids:', ids, on_node.tag
|
||||
key = on_node.tag.category
|
||||
if (key == 'authors' and len(ids) >= 5):
|
||||
if not confirm('<p>'+_('Changing the authors for several books can '
|
||||
'take a while. Are you sure?')
|
||||
+'</p>', 'tag_browser_drop_authors', self.parent()):
|
||||
return
|
||||
elif len(ids) > 15:
|
||||
if not confirm('<p>'+_('Changing the metadata for that many books '
|
||||
'can take a while. Are you sure?')
|
||||
+'</p>', 'tag_browser_many_changes', self.parent()):
|
||||
return
|
||||
|
||||
fm = self.db.metadata_for_field(key)
|
||||
is_multiple = fm['is_multiple']
|
||||
val = on_node.tag.name
|
||||
for id in ids:
|
||||
mi = self.db.get_metadata(id, index_is_id=True)
|
||||
|
||||
# Prepare to ignore the author, unless it is changed. Title is
|
||||
# always ignored -- see the call to set_metadata
|
||||
set_authors = False
|
||||
|
||||
# Author_sort cannot change explicitly. Changing the author might
|
||||
# change it.
|
||||
mi.author_sort = None # Never will change by itself.
|
||||
|
||||
if key == 'authors':
|
||||
mi.authors = [val]
|
||||
set_authors=True
|
||||
elif fm['datatype'] == 'rating':
|
||||
mi.set(key, len(val) * 2)
|
||||
elif fm['is_custom'] and fm['datatype'] == 'series':
|
||||
mi.set(key, val, extra=1.0)
|
||||
elif is_multiple:
|
||||
new_val = mi.get(key, [])
|
||||
if val in new_val:
|
||||
# Fortunately, only one field can change, so the continue
|
||||
# won't break anything
|
||||
continue
|
||||
new_val.append(val)
|
||||
mi.set(key, new_val)
|
||||
else:
|
||||
mi.set(key, val)
|
||||
self.db.set_metadata(id, mi, set_title=False,
|
||||
set_authors=set_authors, commit=False)
|
||||
self.db.commit()
|
||||
self.drag_drop_finished.emit(ids)
|
||||
|
||||
def set_search_restriction(self, s):
|
||||
self.search_restriction = s
|
||||
|
||||
@ -650,12 +625,19 @@ class TagsModel(QAbstractItemModel): # {{{
|
||||
|
||||
def flags(self, index, *args):
|
||||
ans = Qt.ItemIsEnabled|Qt.ItemIsSelectable|Qt.ItemIsEditable
|
||||
if index.isValid() and self.parent(index).isValid():
|
||||
if index.isValid():
|
||||
node = self.data(index, Qt.UserRole)
|
||||
if node.type == TagTreeItem.TAG:
|
||||
fm = self.db.metadata_for_field(node.tag.category)
|
||||
if node.tag.category in \
|
||||
('tags', 'series', 'authors', 'rating', 'publisher') or \
|
||||
(fm['is_custom'] and \
|
||||
fm['datatype'] in ['text', 'rating', 'series']):
|
||||
ans |= Qt.ItemIsDropEnabled
|
||||
return ans
|
||||
|
||||
def supportedDropActions(self):
|
||||
return Qt.CopyAction|Qt.MoveAction
|
||||
return Qt.CopyAction
|
||||
|
||||
def path_for_index(self, index):
|
||||
ans = []
|
||||
|
@ -150,6 +150,7 @@ class Document(QWebPage):
|
||||
self.setObjectName("py_bridge")
|
||||
self.debug_javascript = False
|
||||
self.current_language = None
|
||||
self.loaded_javascript = False
|
||||
|
||||
self.setLinkDelegationPolicy(self.DelegateAllLinks)
|
||||
self.scroll_marks = []
|
||||
@ -175,9 +176,9 @@ class Document(QWebPage):
|
||||
self.set_user_stylesheet()
|
||||
self.misc_config()
|
||||
|
||||
# Load jQuery
|
||||
self.connect(self.mainFrame(), SIGNAL('javaScriptWindowObjectCleared()'),
|
||||
self.load_javascript_libraries)
|
||||
# Load javascript
|
||||
self.mainFrame().javaScriptWindowObjectCleared.connect(
|
||||
self.add_window_objects)
|
||||
|
||||
def set_user_stylesheet(self):
|
||||
raw = config().parse().user_css
|
||||
@ -196,16 +197,20 @@ class Document(QWebPage):
|
||||
if self.do_fit_images:
|
||||
self.javascript('setup_image_scaling_handlers()')
|
||||
|
||||
def add_window_objects(self):
|
||||
self.mainFrame().addToJavaScriptWindowObject("py_bridge", self)
|
||||
self.loaded_javascript = False
|
||||
|
||||
def load_javascript_libraries(self):
|
||||
global bookmarks, referencing, hyphenation, jquery, jquery_scrollTo, hyphenator, images
|
||||
self.mainFrame().addToJavaScriptWindowObject("py_bridge", self)
|
||||
if self.loaded_javascript:
|
||||
return
|
||||
self.loaded_javascript = True
|
||||
if jquery is None:
|
||||
jquery = P('content_server/jquery.js', data=True)
|
||||
self.javascript(jquery)
|
||||
if jquery_scrollTo is None:
|
||||
jquery_scrollTo = P('viewer/jquery_scrollTo.js', data=True)
|
||||
if hyphenator is None:
|
||||
hyphenator = P('viewer/hyphenate/Hyphenator.js', data=True).decode('utf-8')
|
||||
self.javascript(jquery)
|
||||
self.javascript(jquery_scrollTo)
|
||||
if bookmarks is None:
|
||||
bookmarks = P('viewer/bookmarks.js', data=True)
|
||||
@ -224,6 +229,8 @@ class Document(QWebPage):
|
||||
if not lang:
|
||||
lang = default_lang
|
||||
lang = lang.lower()[:2]
|
||||
if hyphenator is None:
|
||||
hyphenator = P('viewer/hyphenate/Hyphenator.js', data=True).decode('utf-8')
|
||||
self.javascript(hyphenator)
|
||||
p = P('viewer/hyphenate/patterns/%s.js'%lang)
|
||||
if not os.path.exists(p):
|
||||
@ -256,6 +263,9 @@ class Document(QWebPage):
|
||||
self.javascript('goto_reference("%s")'%ref)
|
||||
|
||||
def goto_bookmark(self, bm):
|
||||
bm = bm.strip()
|
||||
if bm.startswith('>'):
|
||||
bm = bm[1:].strip()
|
||||
self.javascript('scroll_to_bookmark("%s")'%bm)
|
||||
|
||||
def javascript(self, string, typ=None):
|
||||
@ -641,6 +651,7 @@ class DocumentView(QWebView):
|
||||
# An <iframe> finished loading
|
||||
return
|
||||
self.loading_url = None
|
||||
self.document.load_javascript_libraries()
|
||||
self.document.set_bottom_padding(0)
|
||||
self.document.fit_images()
|
||||
self._size_hint = self.document.mainFrame().contentsSize()
|
||||
@ -804,6 +815,7 @@ class DocumentView(QWebView):
|
||||
def wheelEvent(self, event):
|
||||
if event.delta() < -14:
|
||||
if self.document.at_bottom:
|
||||
self.scroll_by(y=15) # at_bottom can lie on windows
|
||||
if self.manager is not None:
|
||||
self.manager.next_document()
|
||||
event.accept()
|
||||
|
@ -353,6 +353,7 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
|
||||
self.pending_bookmark = bm
|
||||
if spine_index < 0 or spine_index >= len(self.iterator.spine):
|
||||
spine_index = 0
|
||||
self.pending_bookmark = None
|
||||
self.load_path(self.iterator.spine[spine_index])
|
||||
|
||||
def toc_clicked(self, index):
|
||||
@ -695,6 +696,9 @@ def config(defaults=None):
|
||||
c.add_opt('raise_window', ['--raise-window'], default=False,
|
||||
help=_('If specified, viewer window will try to come to the '
|
||||
'front when started.'))
|
||||
c.add_opt('full_screen', ['--full-screen', '--fullscreen', '-f'], default=False,
|
||||
help=_('If specified, viewer window will try to open '
|
||||
'full screen when started.'))
|
||||
c.add_opt('remember_window_size', default=False,
|
||||
help=_('Remember last used window size'))
|
||||
c.add_opt('debug_javascript', ['--debug-javascript'], default=False,
|
||||
@ -726,6 +730,8 @@ def main(args=sys.argv):
|
||||
main.show()
|
||||
if opts.raise_window:
|
||||
main.raise_()
|
||||
if opts.full_screen:
|
||||
main.action_full_screen.trigger()
|
||||
with main:
|
||||
return app.exec_()
|
||||
return 0
|
||||
|
@ -42,6 +42,8 @@ def comments_to_html(comments):
|
||||
Deprecated HTML returns as HTML via BeautifulSoup()
|
||||
|
||||
'''
|
||||
if not comments:
|
||||
return u'<p></p>'
|
||||
if not isinstance(comments, unicode):
|
||||
comments = comments.decode(preferred_encoding, 'replace')
|
||||
|
||||
|
@ -10,6 +10,7 @@ import os, sys, shutil, cStringIO, glob, time, functools, traceback, re
|
||||
from itertools import repeat
|
||||
from math import floor
|
||||
from Queue import Queue
|
||||
from operator import itemgetter
|
||||
|
||||
from PyQt4.QtGui import QImage
|
||||
|
||||
@ -68,7 +69,7 @@ copyfile = os.link if hasattr(os, 'link') else shutil.copyfile
|
||||
class Tag(object):
|
||||
|
||||
def __init__(self, name, id=None, count=0, state=0, avg=0, sort=None,
|
||||
tooltip=None, icon=None):
|
||||
tooltip=None, icon=None, category=None):
|
||||
self.name = name
|
||||
self.id = id
|
||||
self.count = count
|
||||
@ -81,9 +82,11 @@ class Tag(object):
|
||||
tooltip = _('%sAverage rating is %3.1f')%(tooltip, self.avg_rating)
|
||||
self.tooltip = tooltip
|
||||
self.icon = icon
|
||||
self.category = category
|
||||
|
||||
def __unicode__(self):
|
||||
return u'%s:%s:%s:%s:%s'%(self.name, self.count, self.id, self.state, self.tooltip)
|
||||
return u'%s:%s:%s:%s:%s:%s'%(self.name, self.count, self.id, self.state,
|
||||
self.category, self.tooltip)
|
||||
|
||||
def __str__(self):
|
||||
return unicode(self).encode('utf-8')
|
||||
@ -1102,21 +1105,22 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
tooltip = self.custom_column_label_map[label]['name']
|
||||
|
||||
datatype = cat['datatype']
|
||||
avgr = itemgetter(3)
|
||||
item_not_zero_func = lambda x: x[2] > 0
|
||||
if datatype == 'rating':
|
||||
# eliminate the zero ratings line as well as count == 0
|
||||
item_not_zero_func = (lambda x: x[1] > 0 and x[2] > 0)
|
||||
formatter = (lambda x:u'\u2605'*int(x/2))
|
||||
avgr = itemgetter(1)
|
||||
elif category == 'authors':
|
||||
item_not_zero_func = (lambda x: x[2] > 0)
|
||||
# Clean up the authors strings to human-readable form
|
||||
formatter = (lambda x: x.replace('|', ','))
|
||||
else:
|
||||
item_not_zero_func = (lambda x: x[2] > 0)
|
||||
formatter = (lambda x:unicode(x))
|
||||
|
||||
categories[category] = [Tag(formatter(r[1]), count=r[2], id=r[0],
|
||||
avg=r[3], sort=r[4],
|
||||
icon=icon, tooltip=tooltip)
|
||||
avg=avgr(r), sort=r[4], icon=icon,
|
||||
tooltip=tooltip, category=category)
|
||||
for r in data if item_not_zero_func(r)]
|
||||
|
||||
# Needed for legacy databases that have multiple ratings that
|
||||
@ -1148,7 +1152,8 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
WHERE format="%s"'''%fmt,
|
||||
all=False)
|
||||
if count > 0:
|
||||
categories['formats'].append(Tag(fmt, count=count, icon=icon))
|
||||
categories['formats'].append(Tag(fmt, count=count, icon=icon,
|
||||
category='formats'))
|
||||
|
||||
if sort == 'popularity':
|
||||
categories['formats'].sort(key=lambda x: x.count, reverse=True)
|
||||
@ -1194,7 +1199,8 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
if icon_map and 'search' in icon_map:
|
||||
icon = icon_map['search']
|
||||
for srch in saved_searches().names():
|
||||
items.append(Tag(srch, tooltip=saved_searches().lookup(srch), icon=icon))
|
||||
items.append(Tag(srch, tooltip=saved_searches().lookup(srch),
|
||||
icon=icon, category='search'))
|
||||
if len(items):
|
||||
if icon_map is not None:
|
||||
icon_map['search'] = icon_map['search']
|
||||
|
@ -22,6 +22,20 @@ class TagsIcons(dict):
|
||||
raise ValueError('Missing category icon [%s]'%a)
|
||||
self[a] = icon_dict[a]
|
||||
|
||||
category_icon_map = {
|
||||
'authors' : 'user_profile.png',
|
||||
'series' : 'series.png',
|
||||
'formats' : 'book.png',
|
||||
'publisher' : 'publisher.png',
|
||||
'rating' : 'rating.png',
|
||||
'news' : 'news.png',
|
||||
'tags' : 'tags.png',
|
||||
':custom' : 'column.png',
|
||||
':user' : 'drawer.png',
|
||||
'search' : 'search.png'
|
||||
}
|
||||
|
||||
|
||||
class FieldMetadata(dict):
|
||||
'''
|
||||
key: the key to the dictionary is:
|
||||
@ -161,7 +175,7 @@ class FieldMetadata(dict):
|
||||
'datatype':'text',
|
||||
'is_multiple':None,
|
||||
'kind':'field',
|
||||
'name':None,
|
||||
'name':_('Comments'),
|
||||
'search_terms':['comments', 'comment'],
|
||||
'is_custom':False, 'is_category':False}),
|
||||
('cover', {'table':None,
|
||||
|
@ -22,6 +22,7 @@ from calibre.library.server.mobile import MobileServer
|
||||
from calibre.library.server.xml import XMLServer
|
||||
from calibre.library.server.opds import OPDSServer
|
||||
from calibre.library.server.cache import Cache
|
||||
from calibre.library.server.browse import BrowseServer
|
||||
|
||||
|
||||
class DispatchController(object): # {{{
|
||||
@ -53,7 +54,8 @@ class DispatchController(object): # {{{
|
||||
|
||||
# }}}
|
||||
|
||||
class LibraryServer(ContentServer, MobileServer, XMLServer, OPDSServer, Cache):
|
||||
class LibraryServer(ContentServer, MobileServer, XMLServer, OPDSServer, Cache,
|
||||
BrowseServer):
|
||||
|
||||
server_name = __appname__ + '/' + __version__
|
||||
|
||||
|
694
src/calibre/library/server/browse.py
Normal file
@ -0,0 +1,694 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import operator, os, json
|
||||
from binascii import hexlify, unhexlify
|
||||
|
||||
import cherrypy
|
||||
|
||||
from calibre.constants import filesystem_encoding
|
||||
from calibre import isbytestring, force_unicode, fit_image, \
|
||||
prepare_string_for_xml as xml
|
||||
from calibre.utils.ordered_dict import OrderedDict
|
||||
from calibre.utils.filenames import ascii_filename
|
||||
from calibre.utils.config import prefs
|
||||
from calibre.utils.magick import Image
|
||||
from calibre.library.comments import comments_to_html
|
||||
from calibre.library.server import custom_fields_to_display
|
||||
from calibre.library.field_metadata import category_icon_map
|
||||
|
||||
def render_book_list(ids, suffix=''): # {{{
|
||||
pages = []
|
||||
num = len(ids)
|
||||
pos = 0
|
||||
delta = 25
|
||||
while ids:
|
||||
page = list(ids[:delta])
|
||||
pages.append((page, pos))
|
||||
ids = ids[delta:]
|
||||
pos += len(page)
|
||||
page_template = u'''\
|
||||
<div class="page" id="page{0}">
|
||||
<div class="load_data" title="{1}">
|
||||
<span class="url" title="/browse/booklist_page"></span>
|
||||
<span class="start" title="{start}"></span>
|
||||
<span class="end" title="{end}"></span>
|
||||
</div>
|
||||
<div class="loading"><img src="/static/loading.gif" /> {2}</div>
|
||||
<div class="loaded"></div>
|
||||
</div>
|
||||
'''
|
||||
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')) + '…',
|
||||
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 class="navmiddle">
|
||||
<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): # {{{
|
||||
if isinstance(x, unicode):
|
||||
x = x.encode('utf-8')
|
||||
return x
|
||||
# }}}
|
||||
|
||||
def render_rating(rating, container='span', prefix=None): # {{{
|
||||
if rating < 0.1:
|
||||
return '', ''
|
||||
added = 0
|
||||
if prefix is None:
|
||||
prefix = _('Average rating')
|
||||
rstring = xml(_('%s: %.1f stars')% (prefix, rating if rating else 0.0),
|
||||
True)
|
||||
ans = ['<%s class="rating">' % (container)]
|
||||
for i in range(5):
|
||||
n = rating - added
|
||||
x = 'half'
|
||||
if n <= 0.1:
|
||||
x = 'off'
|
||||
elif n >= 0.9:
|
||||
x = 'on'
|
||||
ans.append(
|
||||
u'<img alt="{0}" title="{0}" src="/static/star-{1}.png" />'.format(
|
||||
rstring, x))
|
||||
added += 1
|
||||
ans.append('</%s>'%container)
|
||||
return u''.join(ans), rstring
|
||||
|
||||
# }}}
|
||||
|
||||
def get_category_items(category, items, db, datatype): # {{{
|
||||
|
||||
def item(i):
|
||||
templ = (u'<div title="{4}" class="category-item">'
|
||||
'<div class="category-name">{0}</div><div>{1}</div>'
|
||||
'<div>{2}'
|
||||
'<span class="href">{3}</span></div></div>')
|
||||
rating, rstring = render_rating(i.avg_rating)
|
||||
name = xml(i.name)
|
||||
if datatype == 'rating':
|
||||
name = xml(_('%d stars')%int(i.avg_rating))
|
||||
id_ = i.id
|
||||
if id_ is None:
|
||||
id_ = hexlify(force_unicode(name).encode('utf-8'))
|
||||
id_ = xml(str(id_))
|
||||
desc = ''
|
||||
if i.count > 0:
|
||||
desc += '[' + _('%d books')%i.count + ']'
|
||||
q = i.category
|
||||
if not q:
|
||||
q = category
|
||||
href = '/browse/matches/%s/%s'%(q, id_)
|
||||
return templ.format(xml(name), rating,
|
||||
xml(desc), xml(href), rstring)
|
||||
|
||||
items = list(map(item, items))
|
||||
return '\n'.join(['<div class="category-container">'] + items + ['</div>'])
|
||||
|
||||
# }}}
|
||||
|
||||
class Endpoint(object): # {{{
|
||||
'Manage encoding, mime-type, last modified, cookies, etc.'
|
||||
|
||||
def __init__(self, mimetype='text/html; charset=utf-8', sort_type='category'):
|
||||
self.mimetype = mimetype
|
||||
self.sort_type = sort_type
|
||||
self.sort_kwarg = sort_type + '_sort'
|
||||
self.sort_cookie_name = 'calibre_browse_server_sort_'+self.sort_type
|
||||
|
||||
def __call__(eself, func):
|
||||
|
||||
def do(self, *args, **kwargs):
|
||||
if 'json' not in eself.mimetype:
|
||||
sort_val = None
|
||||
cookie = cherrypy.request.cookie
|
||||
if cookie.has_key(eself.sort_cookie_name):
|
||||
sort_val = cookie[eself.sort_cookie_name].value
|
||||
kwargs[eself.sort_kwarg] = sort_val
|
||||
|
||||
ans = func(self, *args, **kwargs)
|
||||
cherrypy.response.headers['Content-Type'] = eself.mimetype
|
||||
updated = self.db.last_modified()
|
||||
cherrypy.response.headers['Last-Modified'] = \
|
||||
self.last_modified(max(updated, self.build_time))
|
||||
ans = utf8(ans)
|
||||
return ans
|
||||
|
||||
do.__name__ = func.__name__
|
||||
|
||||
return do
|
||||
# }}}
|
||||
|
||||
class BrowseServer(object):
|
||||
|
||||
def add_routes(self, connect):
|
||||
base_href = '/browse'
|
||||
connect('browse', base_href, self.browse_catalog)
|
||||
connect('browse_catalog', base_href+'/category/{category}',
|
||||
self.browse_catalog)
|
||||
connect('browse_category_group',
|
||||
base_href+'/category_group/{category}/{group}',
|
||||
self.browse_category_group)
|
||||
connect('browse_matches',
|
||||
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)
|
||||
connect('browse_details', base_href+'/details/{id}',
|
||||
self.browse_details)
|
||||
connect('browse_book', base_href+'/book/{id}',
|
||||
self.browse_book)
|
||||
connect('browse_category_icon', base_href+'/icon/{name}',
|
||||
self.browse_icon)
|
||||
|
||||
# Templates {{{
|
||||
def browse_template(self, sort, category=True, initial_search=''):
|
||||
|
||||
if not hasattr(self, '__browse_template__') or \
|
||||
self.opts.develop:
|
||||
self.__browse_template__ = \
|
||||
P('content_server/browse/browse.html', data=True).decode('utf-8')
|
||||
|
||||
ans = self.__browse_template__
|
||||
scn = 'calibre_browse_server_sort_'
|
||||
|
||||
if category:
|
||||
sort_opts = [('rating', _('Average rating')), ('name',
|
||||
_('Name')), ('popularity', _('Popularity'))]
|
||||
scn += 'category'
|
||||
else:
|
||||
scn += 'list'
|
||||
fm = self.db.field_metadata
|
||||
sort_opts, added = [], set([])
|
||||
displayed_custom_fields = custom_fields_to_display(self.db)
|
||||
for x in fm.sortable_field_keys():
|
||||
if x in ('ondevice', 'formats', 'sort'):
|
||||
continue
|
||||
if fm[x]['is_custom'] and x not in displayed_custom_fields:
|
||||
continue
|
||||
if x == 'comments' or fm[x]['datatype'] == 'comments':
|
||||
continue
|
||||
n = fm[x]['name']
|
||||
if n not in added:
|
||||
added.add(n)
|
||||
sort_opts.append((x, n))
|
||||
|
||||
ans = ans.replace('{sort_select_label}', xml(_('Sort by')+':'))
|
||||
ans = ans.replace('{sort_cookie_name}', scn)
|
||||
opts = ['<option %svalue="%s">%s</option>' % (
|
||||
'selected="selected" ' if k==sort else '',
|
||||
xml(k), xml(n), ) for k, n in
|
||||
sorted(sort_opts, key=operator.itemgetter(1)) if k and n]
|
||||
ans = ans.replace('{sort_select_options}', ('\n'+' '*20).join(opts))
|
||||
lp = self.db.library_path
|
||||
if isbytestring(lp):
|
||||
lp = force_unicode(lp, filesystem_encoding)
|
||||
if isinstance(ans, unicode):
|
||||
ans = ans.encode('utf-8')
|
||||
ans = ans.replace('{library_name}', xml(os.path.basename(lp)))
|
||||
ans = ans.replace('{library_path}', xml(lp, True))
|
||||
ans = ans.replace('{initial_search}', initial_search)
|
||||
return ans
|
||||
|
||||
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 {{{
|
||||
def browse_icon(self, name='blank.png'):
|
||||
cherrypy.response.headers['Content-Type'] = 'image/png'
|
||||
cherrypy.response.headers['Last-Modified'] = self.last_modified(self.build_time)
|
||||
|
||||
if not hasattr(self, '__browse_icon_cache__'):
|
||||
self.__browse_icon_cache__ = {}
|
||||
if name not in self.__browse_icon_cache__:
|
||||
try:
|
||||
data = I(name, data=True)
|
||||
except:
|
||||
raise cherrypy.HTTPError(404, 'no icon named: %r'%name)
|
||||
img = Image()
|
||||
img.load(data)
|
||||
width, height = img.size
|
||||
scaled, width, height = fit_image(width, height, 48, 48)
|
||||
if scaled:
|
||||
img.size = (width, height)
|
||||
|
||||
self.__browse_icon_cache__[name] = img.export('png')
|
||||
return self.__browse_icon_cache__[name]
|
||||
|
||||
def browse_toplevel(self):
|
||||
categories = self.categories_cache()
|
||||
category_meta = self.db.field_metadata
|
||||
cats = [
|
||||
(_('Newest'), 'newest', 'forward.png'),
|
||||
]
|
||||
|
||||
def getter(x):
|
||||
return category_meta[x]['name'].lower()
|
||||
|
||||
displayed_custom_fields = custom_fields_to_display(self.db)
|
||||
for category in sorted(categories,
|
||||
cmp=lambda x,y: cmp(getter(x), getter(y))):
|
||||
if len(categories[category]) == 0:
|
||||
continue
|
||||
if category == 'formats':
|
||||
continue
|
||||
meta = category_meta.get(category, None)
|
||||
if meta is None:
|
||||
continue
|
||||
if meta['is_custom'] and category not in displayed_custom_fields:
|
||||
continue
|
||||
# get the icon files
|
||||
if category in category_icon_map:
|
||||
icon = category_icon_map[category]
|
||||
elif meta['is_custom']:
|
||||
icon = category_icon_map[':custom']
|
||||
elif meta['kind'] == 'user':
|
||||
icon = category_icon_map[':user']
|
||||
else:
|
||||
icon = 'blank.png'
|
||||
cats.append((meta['name'], category, icon))
|
||||
|
||||
cats = [('<li title="{2} {0}"><img src="{src}" alt="{0}" />'
|
||||
'<span class="label">{0}</span>'
|
||||
'<span class="url">/browse/category/{1}</span></li>')
|
||||
.format(xml(x, True), xml(y), xml(_('Browse books by')),
|
||||
src='/browse/icon/'+z)
|
||||
for x, y, z in cats]
|
||||
|
||||
main = '<div class="toplevel"><h3>{0}</h3><ul>{1}</ul></div>'\
|
||||
.format(_('Choose a category to browse by:'), '\n\n'.join(cats))
|
||||
return self.browse_template('name').format(title='',
|
||||
script='toplevel();', main=main)
|
||||
|
||||
def browse_sort_categories(self, items, sort):
|
||||
if sort not in ('rating', 'name', 'popularity'):
|
||||
sort = 'name'
|
||||
def sorter(x):
|
||||
ans = getattr(x, 'sort', x.name)
|
||||
if hasattr(ans, 'upper'):
|
||||
ans = ans.upper()
|
||||
return ans
|
||||
items.sort(key=sorter)
|
||||
if sort == 'popularity':
|
||||
items.sort(key=operator.attrgetter('count'), reverse=True)
|
||||
elif sort == 'rating':
|
||||
items.sort(key=operator.attrgetter('avg_rating'), reverse=True)
|
||||
return sort
|
||||
|
||||
def browse_category(self, category, sort):
|
||||
categories = self.categories_cache()
|
||||
if category not in categories:
|
||||
raise cherrypy.HTTPError(404, 'category not found')
|
||||
category_meta = self.db.field_metadata
|
||||
category_name = category_meta[category]['name']
|
||||
datatype = category_meta[category]['datatype']
|
||||
|
||||
|
||||
items = categories[category]
|
||||
sort = self.browse_sort_categories(items, sort)
|
||||
|
||||
script = 'true'
|
||||
|
||||
if len(items) <= self.opts.max_opds_ungrouped_items:
|
||||
script = 'false'
|
||||
items = get_category_items(category, items, self.db, datatype)
|
||||
else:
|
||||
getter = lambda x: unicode(getattr(x, 'sort', x.name))
|
||||
starts = set([])
|
||||
for x in items:
|
||||
val = getter(x)
|
||||
if not val:
|
||||
val = u'A'
|
||||
starts.add(val[0].upper())
|
||||
category_groups = OrderedDict()
|
||||
for x in sorted(starts):
|
||||
category_groups[x] = len([y for y in items if
|
||||
getter(y).upper().startswith(x)])
|
||||
items = [(u'<h3 title="{0}">{0} <span>[{2}]</span></h3><div>'
|
||||
u'<div class="loaded" style="display:none"></div>'
|
||||
u'<div class="loading"><img alt="{1}" src="/static/loading.gif" /><em>{1}</em></div>'
|
||||
u'<span class="load_href">{3}</span></div>').format(
|
||||
xml(s, True),
|
||||
xml(_('Loading, please wait'))+'…',
|
||||
unicode(c),
|
||||
xml(u'/browse/category_group/%s/%s'%(category, s)))
|
||||
for s, c in category_groups.items()]
|
||||
items = '\n\n'.join(items)
|
||||
items = u'<div id="groups">\n{0}</div>'.format(items)
|
||||
|
||||
|
||||
|
||||
script = 'category(%s);'%script
|
||||
|
||||
main = u'''
|
||||
<div class="category">
|
||||
<h3>{0}</h3>
|
||||
<a class="navlink" href="/browse"
|
||||
title="{2}">{2} ↑</a>
|
||||
{1}
|
||||
</div>
|
||||
'''.format(
|
||||
xml(_('Browsing by')+': ' + category_name), items,
|
||||
xml(_('Up'), True))
|
||||
|
||||
return self.browse_template(sort).format(title=category_name,
|
||||
script=script, main=main)
|
||||
|
||||
@Endpoint(mimetype='application/json; charset=utf-8')
|
||||
def browse_category_group(self, category=None, group=None, sort=None):
|
||||
if sort == 'null':
|
||||
sort = None
|
||||
if sort not in ('rating', 'name', 'popularity'):
|
||||
sort = 'name'
|
||||
categories = self.categories_cache()
|
||||
if category not in categories:
|
||||
raise cherrypy.HTTPError(404, 'category not found')
|
||||
|
||||
category_meta = self.db.field_metadata
|
||||
datatype = category_meta[category]['datatype']
|
||||
|
||||
if not group:
|
||||
raise cherrypy.HTTPError(404, 'invalid group')
|
||||
|
||||
items = categories[category]
|
||||
entries = []
|
||||
getter = lambda x: unicode(getattr(x, 'sort', x.name))
|
||||
for x in items:
|
||||
val = getter(x)
|
||||
if not val:
|
||||
val = u'A'
|
||||
if val.upper().startswith(group):
|
||||
entries.append(x)
|
||||
|
||||
sort = self.browse_sort_categories(entries, sort)
|
||||
entries = get_category_items(category, entries, self.db, datatype)
|
||||
return json.dumps(entries, ensure_ascii=False)
|
||||
|
||||
|
||||
@Endpoint()
|
||||
def browse_catalog(self, category=None, category_sort=None):
|
||||
'Entry point for top-level, categories and sub-categories'
|
||||
if category == None:
|
||||
ans = self.browse_toplevel()
|
||||
elif category == 'newest':
|
||||
raise cherrypy.InternalRedirect('/browse/matches/newest/dummy')
|
||||
else:
|
||||
ans = self.browse_category(category, category_sort)
|
||||
|
||||
return ans
|
||||
|
||||
# }}}
|
||||
|
||||
# Book Lists {{{
|
||||
|
||||
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',
|
||||
'series')
|
||||
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')
|
||||
fm = self.db.field_metadata
|
||||
try:
|
||||
category_name = fm[category]['name']
|
||||
dt = fm[category]['datatype']
|
||||
except:
|
||||
if category != 'newest':
|
||||
raise
|
||||
category_name = _('Newest')
|
||||
dt = None
|
||||
|
||||
hide_sort = 'true' if dt == 'series' else '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:
|
||||
q = category
|
||||
if q == 'news':
|
||||
q = 'tags'
|
||||
ids = self.db.get_books_for_category(q, cid)
|
||||
|
||||
items = [self.db.data._data[x] for x in ids]
|
||||
if category == 'newest':
|
||||
list_sort = 'timestamp'
|
||||
if dt == 'series':
|
||||
list_sort = category
|
||||
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()
|
||||
try:
|
||||
fmt = pf if pf in fmts else fmts[0]
|
||||
except:
|
||||
fmt = None
|
||||
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'] = ''
|
||||
if fmts and fmt:
|
||||
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(f, fname, id_, f.upper()) for f in
|
||||
other_fmts]
|
||||
ofmts = ', '.join(ofmts)
|
||||
args['other_formats'] = u'<strong>%s: </strong>' % \
|
||||
_('Other formats') + ofmts
|
||||
|
||||
args['details_href'] = '/browse/details/'+str(id_)
|
||||
|
||||
if fmt:
|
||||
href = '/get/%s/%s_%d.%s'%(
|
||||
fmt, fname, id_, fmt)
|
||||
rt = xml(_('Read %s in the %s format')%(args['title'],
|
||||
fmt.upper()), True)
|
||||
|
||||
args['get_button'] = \
|
||||
'<a href="%s" class="read" title="%s">%s</a>' % \
|
||||
(xml(href, True), rt, xml(_('Get')))
|
||||
else:
|
||||
args['get_button'] = ''
|
||||
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['details'] = xml(_('Details'), True)
|
||||
args['details_tt'] = xml(_('Show book details'), True)
|
||||
args['permalink'] = xml(_('Permalink'), True)
|
||||
args['permalink_tt'] = xml(_('A permanent link to this book'), True)
|
||||
|
||||
summs.append(self.browse_summary_template.format(**args))
|
||||
|
||||
|
||||
return json.dumps('\n'.join(summs), ensure_ascii=False)
|
||||
|
||||
def browse_render_details(self, id_):
|
||||
try:
|
||||
mi = self.db.get_metadata(id_, index_is_id=True)
|
||||
except:
|
||||
return _('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 = [], []
|
||||
displayed_custom_fields = custom_fields_to_display(self.db)
|
||||
for field, m in list(mi.get_all_standard_metadata(False).items()) + \
|
||||
list(mi.get_all_user_metadata(False).items()):
|
||||
if m['is_custom'] and field not in displayed_custom_fields:
|
||||
continue
|
||||
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))
|
||||
|
||||
return self.browse_details_template.format(id=id_,
|
||||
title=xml(mi.title, True), fields=fields,
|
||||
formats=args['formats'], comments=comments)
|
||||
|
||||
@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)
|
||||
|
||||
ans = self.browse_render_details(id_)
|
||||
|
||||
return json.dumps(ans, ensure_ascii=False)
|
||||
|
||||
|
||||
@Endpoint()
|
||||
def browse_book(self, id=None, category_sort=None):
|
||||
try:
|
||||
id_ = int(id)
|
||||
except:
|
||||
raise cherrypy.HTTPError(404, 'invalid id: %r'%id)
|
||||
|
||||
ans = self.browse_render_details(id_)
|
||||
return self.browse_template('').format(
|
||||
title='', script='book();', main=ans)
|
||||
|
||||
|
||||
# }}}
|
||||
|
||||
# Search {{{
|
||||
@Endpoint(sort_type='list')
|
||||
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)
|
||||
|
||||
# }}}
|
||||
|
||||
|
@ -29,6 +29,11 @@ class Cache(object):
|
||||
|
||||
|
||||
def categories_cache(self, restrict_to=frozenset([])):
|
||||
base_restriction = self.search_cache('')
|
||||
if restrict_to:
|
||||
restrict_to = frozenset(restrict_to).intersection(base_restriction)
|
||||
else:
|
||||
restrict_to = base_restriction
|
||||
old = self._category_cache.pop(frozenset(restrict_to), None)
|
||||
if old is None or old[0] <= self.db.last_modified():
|
||||
categories = self.db.get_categories(ids=restrict_to)
|
||||
|
@ -5,18 +5,15 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import re, os, cStringIO
|
||||
import re, os
|
||||
|
||||
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.utils.date import fromtimestamp
|
||||
from calibre.library.caches import SortKeyGenerator
|
||||
from calibre.utils.magick.draw import save_cover_data_to, Image, \
|
||||
thumbnail as generate_thumbnail
|
||||
|
||||
class CSSortKeyGenerator(SortKeyGenerator):
|
||||
|
||||
@ -35,9 +32,10 @@ class ContentServer(object):
|
||||
|
||||
def add_routes(self, connect):
|
||||
connect('root', '/', self.index)
|
||||
connect('old', '/old', self.old)
|
||||
connect('get', '/get/{what}/{id}', self.get,
|
||||
conditions=dict(method=["GET", "HEAD"]))
|
||||
connect('static', '/static/{name}', self.static,
|
||||
connect('static', '/static/{name:.*?}', self.static,
|
||||
conditions=dict(method=["GET", "HEAD"]))
|
||||
|
||||
# Utility methods {{{
|
||||
@ -76,8 +74,13 @@ class ContentServer(object):
|
||||
id = int(match.group())
|
||||
if not self.db.has_id(id):
|
||||
raise cherrypy.HTTPError(400, 'id:%d does not exist in database'%id)
|
||||
if what == 'thumb':
|
||||
return self.get_cover(id, thumbnail=True)
|
||||
if what == 'thumb' or what.startswith('thumb_'):
|
||||
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':
|
||||
return self.get_cover(id)
|
||||
return self.get_format(id, what)
|
||||
@ -123,38 +126,43 @@ class ContentServer(object):
|
||||
|
||||
return self.static('index.html')
|
||||
|
||||
def old(self, **kwargs):
|
||||
return self.static('index.html')
|
||||
|
||||
# Actually get content from the database {{{
|
||||
def get_cover(self, id, thumbnail=False):
|
||||
cover = self.db.cover(id, index_is_id=True, as_file=False)
|
||||
if cover is None:
|
||||
cover = self.default_cover
|
||||
def get_cover(self, id, thumbnail=False, thumb_width=60, thumb_height=80):
|
||||
try:
|
||||
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
|
||||
cover = self.db.cover(id, index_is_id=True, as_file=True)
|
||||
if cover is None:
|
||||
cover = self.default_cover
|
||||
updated = self.build_time
|
||||
else:
|
||||
with cover as f:
|
||||
updated = fromtimestamp(os.fstat(f.fileno()).st_mtime)
|
||||
cover = f.read()
|
||||
cherrypy.response.headers['Last-Modified'] = self.last_modified(updated)
|
||||
try:
|
||||
f = cStringIO.StringIO(cover)
|
||||
try:
|
||||
im = PILImage.open(f)
|
||||
except IOError:
|
||||
raise cherrypy.HTTPError(404, 'No valid cover found')
|
||||
width, height = im.size
|
||||
|
||||
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,
|
||||
60 if thumbnail else self.max_cover_width,
|
||||
80 if thumbnail else self.max_cover_height)
|
||||
thumb_width if thumbnail else self.max_cover_width,
|
||||
thumb_height if thumbnail else self.max_cover_height)
|
||||
if not scaled:
|
||||
return cover
|
||||
im = im.resize((int(width), int(height)), PILImage.ANTIALIAS)
|
||||
of = cStringIO.StringIO()
|
||||
im.convert('RGB').save(of, 'JPEG')
|
||||
return of.getvalue()
|
||||
return save_cover_data_to(img, 'img.jpg', return_data=True,
|
||||
resize_to=(width, height))
|
||||
except Exception, err:
|
||||
import traceback
|
||||
cherrypy.log.error('Failed to generate cover:')
|
||||
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):
|
||||
format = format.upper()
|
||||
|
@ -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.ebooks.metadata import fmt_sidx
|
||||
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.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): # {{{
|
||||
div = DIV(id='search_box')
|
||||
form = FORM('Show ', method='get', action='mobile')
|
||||
form.set('accept-charset', 'UTF-8')
|
||||
|
||||
div.append(form)
|
||||
|
||||
num_select = SELECT(name='num')
|
||||
@ -193,6 +195,8 @@ class MobileServer(object):
|
||||
raise cherrypy.HTTPError(400, 'num: %s is not an integer'%num)
|
||||
if not search:
|
||||
search = ''
|
||||
if isbytestring(search):
|
||||
search = search.decode('UTF-8')
|
||||
ids = self.db.search_getting_ids(search.strip(), self.search_restriction)
|
||||
FM = self.db.FIELD_MAP
|
||||
items = [r for r in iter(self.db) if r[FM['id']] in ids]
|
||||
|
@ -18,7 +18,7 @@ from calibre.constants import __appname__
|
||||
from calibre.ebooks.metadata import fmt_sidx
|
||||
from calibre.library.comments import comments_to_html
|
||||
from calibre.library.server import custom_fields_to_display
|
||||
from calibre.library.server.utils import format_tag_string
|
||||
from calibre.library.server.utils import format_tag_string, Offsets
|
||||
from calibre import guess_type
|
||||
from calibre.utils.ordered_dict import OrderedDict
|
||||
|
||||
@ -321,26 +321,6 @@ class CategoryGroupFeed(NavFeed):
|
||||
self.root.append(CATALOG_GROUP_ENTRY(item, which, base_href, version, updated))
|
||||
|
||||
|
||||
class OPDSOffsets(object):
|
||||
|
||||
def __init__(self, offset, delta, total):
|
||||
if offset < 0:
|
||||
offset = 0
|
||||
if offset >= total:
|
||||
raise cherrypy.HTTPError(404, 'Invalid offset: %r'%offset)
|
||||
last_allowed_index = total - 1
|
||||
last_current_index = offset + delta - 1
|
||||
self.offset = offset
|
||||
self.next_offset = last_current_index + 1
|
||||
if self.next_offset > last_allowed_index:
|
||||
self.next_offset = -1
|
||||
self.previous_offset = self.offset - delta
|
||||
if self.previous_offset < 0:
|
||||
self.previous_offset = 0
|
||||
self.last_offset = last_allowed_index - delta
|
||||
if self.last_offset < 0:
|
||||
self.last_offset = 0
|
||||
|
||||
|
||||
class OPDSServer(object):
|
||||
|
||||
@ -374,7 +354,7 @@ class OPDSServer(object):
|
||||
items = [x for x in self.db.data.iterall() if x[idx] in ids]
|
||||
self.sort(items, sort_by, ascending)
|
||||
max_items = self.opts.max_opds_items
|
||||
offsets = OPDSOffsets(offset, max_items, len(items))
|
||||
offsets = Offsets(offset, max_items, len(items))
|
||||
items = items[offsets.offset:offsets.offset+max_items]
|
||||
updated = self.db.last_modified()
|
||||
cherrypy.response.headers['Last-Modified'] = self.last_modified(updated)
|
||||
@ -448,7 +428,7 @@ class OPDSServer(object):
|
||||
id_ = 'calibre-category-group-feed:'+category+':'+which
|
||||
|
||||
max_items = self.opts.max_opds_items
|
||||
offsets = OPDSOffsets(offset, max_items, len(items))
|
||||
offsets = Offsets(offset, max_items, len(items))
|
||||
items = list(items)[offsets.offset:offsets.offset+max_items]
|
||||
|
||||
cherrypy.response.headers['Last-Modified'] = self.last_modified(updated)
|
||||
@ -495,7 +475,7 @@ class OPDSServer(object):
|
||||
|
||||
if len(items) <= MAX_ITEMS:
|
||||
max_items = self.opts.max_opds_items
|
||||
offsets = OPDSOffsets(offset, max_items, len(items))
|
||||
offsets = Offsets(offset, max_items, len(items))
|
||||
items = list(items)[offsets.offset:offsets.offset+max_items]
|
||||
ans = CategoryFeed(items, which, id_, updated, version, offsets,
|
||||
page_url, up_url, self.db)
|
||||
@ -516,7 +496,7 @@ class OPDSServer(object):
|
||||
getattr(y, 'sort', y.name).startswith(x)])
|
||||
items = [Group(x, y) for x, y in category_groups.items()]
|
||||
max_items = self.opts.max_opds_items
|
||||
offsets = OPDSOffsets(offset, max_items, len(items))
|
||||
offsets = Offsets(offset, max_items, len(items))
|
||||
items = items[offsets.offset:offsets.offset+max_items]
|
||||
ans = CategoryGroupFeed(items, which, id_, updated, version, offsets,
|
||||
page_url, up_url)
|
||||
|
@ -13,6 +13,28 @@ from calibre import strftime as _strftime, prints
|
||||
from calibre.utils.date import now as nowf
|
||||
from calibre.utils.config import tweaks
|
||||
|
||||
class Offsets(object):
|
||||
'Calculate offsets for a paginated view'
|
||||
|
||||
def __init__(self, offset, delta, total):
|
||||
if offset < 0:
|
||||
offset = 0
|
||||
if offset >= total:
|
||||
raise cherrypy.HTTPError(404, 'Invalid offset: %r'%offset)
|
||||
last_allowed_index = total - 1
|
||||
last_current_index = offset + delta - 1
|
||||
self.slice_upper_bound = offset+delta
|
||||
self.offset = offset
|
||||
self.next_offset = last_current_index + 1
|
||||
if self.next_offset > last_allowed_index:
|
||||
self.next_offset = -1
|
||||
self.previous_offset = self.offset - delta
|
||||
if self.previous_offset < 0:
|
||||
self.previous_offset = 0
|
||||
self.last_offset = last_allowed_index - delta
|
||||
if self.last_offset < 0:
|
||||
self.last_offset = 0
|
||||
|
||||
|
||||
def expose(func):
|
||||
|
||||
|
@ -49,6 +49,8 @@ class XMLServer(object):
|
||||
|
||||
if not search:
|
||||
search = ''
|
||||
if isbytestring(search):
|
||||
search = search.decode('UTF-8')
|
||||
|
||||
ids = self.db.search_getting_ids(search.strip(), self.search_restriction)
|
||||
|
||||
|
@ -24,6 +24,7 @@ Environment variables
|
||||
* ``CALIBRE_OVERRIDE_DATABASE_PATH`` - allows you to specify the full path to metadata.db. Using this variable you can have metadata.db be in a location other than the library folder. Useful if your library folder is on a networked drive that does not support file locking.
|
||||
* ``CALIBRE_DEVELOP_FROM`` - Used to run from a calibre development environment. See :ref:`develop`.
|
||||
* ``CALIBRE_OVERRIDE_LANG`` - Used to force the language used by the interface (ISO 639 language code)
|
||||
* ``CALIBRE_DISABLE_UDISKS`` - Used to disable the use of udisks for mounting/ejecting. Set it to 1 to use calibre-mount-helper instead.
|
||||
* ``SYSFS_PATH`` - Use if sysfs is mounted somewhere other than /sys
|
||||
* ``http_proxy`` - Used on linux to specify an HTTP proxy
|
||||
|
||||
|