diff --git a/resources/content_server/browse/browse.css b/resources/content_server/browse/browse.css index 1243795e55..75832e47f9 100644 --- a/resources/content_server/browse/browse.css +++ b/resources/content_server/browse/browse.css @@ -355,6 +355,25 @@ h2.library_name { color: red; } +#booklist > #pagelist { display: none; } + +#goto_page_dialog ul { + list-style-type: none; + font-size: medium; +} + +#goto_page_dialog li { + margin-bottom: 1.5ex; +} + +#goto_page_dialog a { + text-decoration: none; + color: blue; +} + +#goto_page_dialog a:hover { + color: red; +} #booklist .left .ui-button-text { font-size: medium; diff --git a/resources/content_server/browse/browse.html b/resources/content_server/browse/browse.html index 6d4c79c4c9..de78e432d7 100644 --- a/resources/content_server/browse/browse.html +++ b/resources/content_server/browse/browse.html @@ -96,5 +96,6 @@
+
diff --git a/resources/content_server/browse/browse.js b/resources/content_server/browse/browse.js index e0585a9afd..2d9bc01082 100644 --- a/resources/content_server/browse/browse.js +++ b/resources/content_server/browse/browse.js @@ -202,6 +202,23 @@ function previous_page() { else last_page(); } +function gp_internal(id) { + var gp = $('#goto_page_dialog'); + gp.dialog('close'); + var elem = $("#booklist #" + id); + load_page(elem); +} + +function goto_page() { + var gp = $('#goto_page_dialog'); + var pl = $('#booklist > #pagelist'); + gp.html(pl.html()); + gp.dialog('option', 'title', pl.attr('title')); + gp.dialog('option', 'height', $(window).height() - 100); + gp.dialog('open'); + +} + function load_page(elem) { if (elem.is(":visible")) return; var ld = elem.find('.load_data'); @@ -251,6 +268,12 @@ function booklist(hide_sort) { modal: true, show: 'slide' }); + $("#goto_page_dialog").dialog({ + autoOpen: false, + modal: true, + show: 'slide' + }); + first_page(); } diff --git a/resources/recipes/al_jazeera.recipe b/resources/recipes/al_jazeera.recipe index fd5f07973d..133a793191 100644 --- a/resources/recipes/al_jazeera.recipe +++ b/resources/recipes/al_jazeera.recipe @@ -1,10 +1,8 @@ -#!/usr/bin/env python - __license__ = 'GPL v3' -__copyright__ = '2009, Darko Miletic ' +__copyright__ = '2009-2010, Darko Miletic ' ''' -aljazeera.net +english.aljazeera.net ''' from calibre.web.feeds.news import BasicNewsRecipe @@ -12,41 +10,59 @@ class AlJazeera(BasicNewsRecipe): title = 'Al Jazeera in English' __author__ = 'Darko Miletic' description = 'News from Middle East' - language = 'en' - + language = 'en' publisher = 'Al Jazeera' category = 'news, politics, middle east' - simultaneous_downloads = 1 - delay = 4 - oldest_article = 1 + delay = 1 + oldest_article = 2 max_articles_per_feed = 100 no_stylesheets = True encoding = 'iso-8859-1' - remove_javascript = True use_embedded_content = False + extra_css = """ + body{font-family: Arial,sans-serif} + #ctl00_cphBody_dvSummary{font-weight: bold} + #dvArticleDate{font-size: small; color: #999999} + """ + conversion_options = { + 'comment' : description + , 'tags' : category + , 'publisher' : publisher + , 'language' : language + } - html2lrf_options = [ - '--comment', description - , '--category', category - , '--publisher', publisher - , '--ignore-tables' - ] - - html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"\nlinearize_table=True' - - keep_only_tags = [dict(name='div', attrs={'id':'ctl00_divContent'})] + keep_only_tags = [ + dict(attrs={'id':['DetailedTitle','ctl00_cphBody_dvSummary','dvArticleDate']}) + ,dict(name='td',attrs={'class':'DetailedSummary'}) + ] remove_tags = [ - dict(name=['object','link']) + dict(name=['object','link','table','meta','base','iframe','embed']) ,dict(name='td', attrs={'class':['MostActiveDescHeader','MostActiveDescBody']}) ] feeds = [(u'AL JAZEERA ENGLISH (AJE)', u'http://english.aljazeera.net/Services/Rss/?PostingId=2007731105943979989' )] + def get_article_url(self, article): + artlurl = article.get('link', None) + return artlurl.replace('http://english.aljazeera.net//','http://english.aljazeera.net/') + def preprocess_html(self, soup): for item in soup.findAll(style=True): del item['style'] for item in soup.findAll(face=True): del item['face'] + td = soup.find('td',attrs={'class':'DetailedSummary'}) + if td: + td.name = 'div' + spn = soup.find('span',attrs={'id':'DetailedTitle'}) + if spn: + spn.name='h1' + for itm in soup.findAll('span', attrs={'id':['dvArticleDate','ctl00_cphBody_lblDate']}): + itm.name = 'div' + for alink in soup.findAll('a'): + if alink.string is not None: + tstr = alink.string + alink.replaceWith(tstr) return soup diff --git a/resources/recipes/globes_co_il.recipe b/resources/recipes/globes_co_il.recipe new file mode 100644 index 0000000000..fdbf79f80d --- /dev/null +++ b/resources/recipes/globes_co_il.recipe @@ -0,0 +1,47 @@ +from calibre.web.feeds.news import BasicNewsRecipe +from calibre.ebooks.BeautifulSoup import re + +class AdvancedUserRecipe1283848012(BasicNewsRecipe): + description = 'This is Globes.co.il.' + cover_url = 'http://www.the7eye.org.il/SiteCollectionImages/BAKTANA/arye_avnery_010709_377.jpg' + title = u'Globes' + language = 'he' + __author__ = 'marbs' + extra_css='img {max-width:100%;} body{direction: rtl;max-width:100%;}title{direction: rtl; } article_description{direction: rtl; }, a.article{direction: rtl;max-width:100%;} calibre_feed_description{direction: rtl; }' + simultaneous_downloads = 5 + remove_javascript = True + timefmt = '[%a, %d %b, %Y]' + oldest_article = 1 + max_articles_per_feed = 100 + remove_attributes = ['width','style'] + + + feeds = [(u'שוק ההון', u'http://www.globes.co.il/webservice/rss/rssfeeder.asmx/FeederNode?iID=585'), + (u'נדל"ן', u'http://www.globes.co.il/webservice/rss/rssfeeder.asmx/FeederNode?iID=607'), + (u'וול סטריט ושווקי העולם', u'http://www.globes.co.il/webservice/rss/rssfeeder.asmx/FeederNode?iID=1225'), + (u'ניתוח טכני', u'http://www.globes.co.il/webservice/rss/rssfeeder.asmx/FeederNode?iID=1294'), + (u'היי טק', u'http://www.globes.co.il/webservice/rss/rssfeeder.asmx/FeederNode?iID=594'), + (u'נתח שוק וצרכנות', u'http://www.globes.co.il/webservice/rss/rssfeeder.asmx/FeederNode?iID=821'), + (u'דין וחשבון', u'http://www.globes.co.il/webservice/rss/rssfeeder.asmx/FeederNode?iID=829'), + (u'רכב', u'http://www.globes.co.il/webservice/rss/rssfeeder.asmx/FeederNode?iID=3220'), + (u'דעות', u'http://www.globes.co.il/webservice/rss/rssfeeder.asmx/FeederNode?iID=845'), + (u'קניון המניות - טור שבועי', u'http://www.globes.co.il/webservice/rss/rssfeeder.asmx/FeederNode?iID=3175'), + (u'סביבה', u'http://www.globes.co.il/webservice/rss/rssfeeder.asmx/FeederNode?iID=3221')] + + def print_version(self, url): + split1 = url.split("=") + print_url = 'http://www.globes.co.il/serve/globes/printwindow.asp?did=' + split1[1] + return print_url + + + def preprocess_html(self, soup): + soup.find('tr',attrs={'bgcolor':'black'}).findPrevious('tr').extract() + soup.find('tr',attrs={'bgcolor':'black'}).extract() + return soup + + def fixChars(self,string): + # Replace lsquo (\x91) + fixed = re.sub("■","■",string) + return fixed + + diff --git a/resources/recipes/hannoversche_zeitung.recipe b/resources/recipes/hannoversche_zeitung.recipe new file mode 100644 index 0000000000..8c0da596e5 --- /dev/null +++ b/resources/recipes/hannoversche_zeitung.recipe @@ -0,0 +1,38 @@ +from calibre.web.feeds.news import BasicNewsRecipe + +class AdvancedUserRecipe1287519083(BasicNewsRecipe): + title = u'Hannoversche Allgemeine Zeitung' + oldest_article = 1 + __author__ = 'Artemis' + max_articles_per_feed = 30 + language = 'de' + no_stylesheets = True + + feeds = [ + #(u'Schlagzeilen', u'http://www.haz.de/rss/feed/haz_schlagzeilen'), + (u'Politik', u'http://www.haz.de/rss/feed/haz_politik'), + (u'Wirtschaft', u'http://www.haz.de/rss/feed/haz_wirtschaft'), + (u'Panorama', u'http://www.haz.de/rss/feed/haz_panorama'), + (u'Wissen', u'http://www.haz.de/rss/feed/haz_wissen'), + (u'Kultur', u'http://www.haz.de/rss/feed/haz_kultur'), + (u'Sp\xe4tvorstellung', u'http://www.haz.de/rss/feed/haz_spaetvorstellung'), + (u'Hannover & Region', u'http://www.haz.de/rss/feed/haz_hannoverregion'), + (u'Netzgefl\xfcster', u'http://www.haz.de/rss/feed/haz_netzgefluester'), + (u'Meinung', u'http://www.haz.de/rss/feed/haz_meinung'), + (u'ZiSH', u'http://www.haz.de/rss/feed/haz_zish'), + (u'Medien', u'http://www.haz.de/rss/feed/haz_medien'), + #(u'Sport', u'http://www.haz.de/rss/feed/haz_sport'), + #(u'Hannover 96', u'http://www.haz.de/rss/feed/haz_hannover96') + ] + + remove_tags_before =dict(id='modul_artikel') + remove_tags_after =dict(id='articlecontent') + + remove_tags = dict(id='articlesidebar') + + remove_tags = [ + dict(name='div', attrs={'class':['articlecomment', + 'articlebookmark', 'teaser_anzeige', 'teaser_umfrage', + 'navigation', 'subnavigation']}) + ] + diff --git a/resources/recipes/irish_times.recipe b/resources/recipes/irish_times.recipe index 14f31cf45f..0ac130ed7a 100644 --- a/resources/recipes/irish_times.recipe +++ b/resources/recipes/irish_times.recipe @@ -13,7 +13,6 @@ class IrishTimes(BasicNewsRecipe): language = 'en_IE' timefmt = ' (%A, %B %d, %Y)' - oldest_article = 3 no_stylesheets = True simultaneous_downloads= 1 @@ -35,12 +34,11 @@ class IrishTimes(BasicNewsRecipe): def print_version(self, url): if url.count('rss.feedsportal.com'): - u = 'http://www.irishtimes.com' + \ - (((url[69:].replace('0C','/')).replace('0A','0'))).replace('0Bhtml/story01..htm','_pf.html') + u = 'http://www.irishtimes.com' + \ + (((url[69:].replace('0C','/')).replace('0A','0'))).replace('0Bhtml/story01.htm','_pf.html') else: u = url.replace('.html','_pf.html') return u - def get_article_url(self, article): return article.link diff --git a/resources/recipes/rds.recipe b/resources/recipes/rds.recipe new file mode 100644 index 0000000000..b77e4804a1 --- /dev/null +++ b/resources/recipes/rds.recipe @@ -0,0 +1,18 @@ +from calibre.web.feeds.news import BasicNewsRecipe + +class AdvancedUserRecipe1290013720(BasicNewsRecipe): + title = u'RDS' + __author__ = 'Nexus' + language = 'en_CA' + description = 'Hockey News' + oldest_article = 7 + max_articles_per_feed = 25 + no_stylesheets = True + remove_tags = [dict(name='div', attrs={'id':'rdsWrap'}), + dict(name='table', attrs={'id':'aVoir'}), + dict(name='div', attrs={'id':'imageChronique'})] + keep_only_tags = [dict(name='div', attrs={'id':['enteteChronique']}), + dict(name='div', attrs={'id':['contenuChronique']})] + + + feeds = [(u'RDS', u'http://www.rds.ca/hockey/fildepresse_rds.xml')] diff --git a/resources/recipes/thn.recipe b/resources/recipes/thn.recipe new file mode 100644 index 0000000000..5e812fbbdf --- /dev/null +++ b/resources/recipes/thn.recipe @@ -0,0 +1,19 @@ +from calibre.web.feeds.news import BasicNewsRecipe + +class AdvancedUserRecipe1289990851(BasicNewsRecipe): + title = u'The Hockey News' + language = 'en_CA' + __author__ = 'Nexus' + oldest_article = 7 + max_articles_per_feed = 25 + no_stylesheets = True + remove_tags = [dict(name='div', attrs={'class':'article_info'}), + dict(name='div', attrs={'class':'photo_details'}), + dict(name='div', attrs={'class':'tool_menu'}), + dict(name='div', attrs={'id':'comments_container'}), + dict(name='div', attrs={'id':'wrapper'})] + keep_only_tags = [dict(name='h1', attrs={'class':['headline']}), + dict(name='div', attrs={'class':['box_container']})] + + feeds = [(u'THN', u'http://www.thehockeynews.com/rss/all_categories.xml')] + diff --git a/src/calibre/ebooks/html/input.py b/src/calibre/ebooks/html/input.py index fa1de39410..059aeca324 100644 --- a/src/calibre/ebooks/html/input.py +++ b/src/calibre/ebooks/html/input.py @@ -269,11 +269,6 @@ class HTMLInput(InputFormatPlugin): ) ), - OptionRecommendation(name='unwrap_factor', recommended_value=0.0, - help=_('Average line length for line breaking if the HTML is from a ' - 'previous partial conversion of a PDF file. Default is %default ' - 'which disables this.')), - ]) def convert(self, stream, opts, file_ext, log, diff --git a/src/calibre/ebooks/snb/snbfile.py b/src/calibre/ebooks/snb/snbfile.py index ed5aa45c08..e42533f241 100644 --- a/src/calibre/ebooks/snb/snbfile.py +++ b/src/calibre/ebooks/snb/snbfile.py @@ -118,8 +118,8 @@ class SNBFile: return False if self.rev80 != SNBFile.REV80: return False - if self.revA3 != SNBFile.REVA3: - return False +# if self.revA3 != SNBFile.REVA3: +# return False if self.revZ1 != SNBFile.REVZ1: return False if self.revZ2 != SNBFile.REVZ2: diff --git a/src/calibre/gui2/device.py b/src/calibre/gui2/device.py index 8d84f69249..048b6e6235 100644 --- a/src/calibre/gui2/device.py +++ b/src/calibre/gui2/device.py @@ -20,8 +20,7 @@ from calibre.gui2.dialogs.choose_format import ChooseFormatDialog from calibre.utils.ipc.job import BaseJob from calibre.devices.scanner import DeviceScanner from calibre.gui2 import config, error_dialog, Dispatcher, dynamic, \ - warning_dialog, \ - question_dialog, info_dialog, choose_dir + warning_dialog, info_dialog, choose_dir from calibre.ebooks.metadata import authors_to_string from calibre import preferred_encoding, prints, force_unicode from calibre.utils.filenames import ascii_filename @@ -665,6 +664,16 @@ class DeviceMixin(object): # {{{ if tweaks['auto_connect_to_folder']: self.connect_to_folder_named(tweaks['auto_connect_to_folder']) + def auto_convert_question(self, msg, autos): + autos = u'\n'.join(map(unicode, map(force_unicode, autos))) + return self.ask_a_yes_no_question( + _('No suitable formats'), msg, + buttons=QMessageBox.Yes|QMessageBox.Cancel, + ans_when_user_unavailable=True, + det_msg=autos, + show_copy_button=False + ) + def set_default_thumbnail(self, height): img = I('book.png', data=True) self.default_thumbnail = thumbnail(img, height, height) @@ -978,11 +987,9 @@ class DeviceMixin(object): # {{{ bad += auto else: autos = [self.library_view.model().db.title(id, index_is_id=True) for id in auto] - autos = '\n'.join('%s'%i for i in autos) - if question_dialog(self, _('No suitable formats'), + if self.auto_convert_question( _('Auto convert the following books before sending via ' - 'email?'), det_msg=autos, - buttons=QMessageBox.Yes|QMessageBox.Cancel): + 'email?'), autos): self.iactions['Convert Books'].auto_convert_mail(to, fmts, delete_from_library, auto, format) if bad: @@ -1085,11 +1092,9 @@ class DeviceMixin(object): # {{{ break if format is not None: autos = [self.library_view.model().db.title(id, index_is_id=True) for id in auto] - autos = '\n'.join('%s'%i for i in autos) - if question_dialog(self, _('No suitable formats'), + if self.auto_convert_question( _('Auto convert the following books before uploading to ' - 'the device?'), det_msg=autos, - buttons=QMessageBox.Yes|QMessageBox.Cancel): + 'the device?'), autos): self.iactions['Convert Books'].auto_convert_catalogs(auto, format) files = [f for f in files if f is not None] if not files: @@ -1170,11 +1175,9 @@ class DeviceMixin(object): # {{{ break if format is not None: autos = [self.library_view.model().db.title(id, index_is_id=True) for id in auto] - autos = '\n'.join('%s'%i for i in autos) - if question_dialog(self, _('No suitable formats'), + if self.auto_convert_question( _('Auto convert the following books before uploading to ' - 'the device?'), det_msg=autos, - buttons=QMessageBox.Yes|QMessageBox.Cancel): + 'the device?'), autos): self.iactions['Convert Books'].auto_convert_news(auto, format) files = [f for f in files if f is not None] for f in files: @@ -1289,11 +1292,9 @@ class DeviceMixin(object): # {{{ bad += auto else: autos = [self.library_view.model().db.title(id, index_is_id=True) for id in auto] - autos = '\n'.join('%s'%i for i in autos) - if question_dialog(self, _('No suitable formats'), + if self.auto_convert_question( _('Auto convert the following books before uploading to ' - 'the device?'), det_msg=autos, - buttons=QMessageBox.Yes|QMessageBox.Cancel): + 'the device?'), autos): self.iactions['Convert Books'].auto_convert(auto, on_card, format) if bad: diff --git a/src/calibre/gui2/layout.py b/src/calibre/gui2/layout.py index c6177ed882..fd42bfe671 100644 --- a/src/calibre/gui2/layout.py +++ b/src/calibre/gui2/layout.py @@ -315,6 +315,9 @@ class ToolBar(QToolBar): # {{{ self.child_bar.addWidget(self.spacers[1]) if gprefs['show_child_bar']: self.addWidget(self.spacers[3]) + else: + for s in self.spacers[2:]: + s.setVisible(False) def setup_tool_button(self, ac, menu_mode=None): ch = self.widgetForAction(ac) diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py index 0ae15b0caa..13bba4f27c 100644 --- a/src/calibre/gui2/ui.py +++ b/src/calibre/gui2/ui.py @@ -26,7 +26,8 @@ from calibre.utils.ipc.server import Server from calibre.library.database2 import LibraryDatabase2 from calibre.customize.ui import interface_actions from calibre.gui2 import error_dialog, GetMetadata, open_local_file, \ - gprefs, max_available_height, config, info_dialog, Dispatcher + gprefs, max_available_height, config, info_dialog, Dispatcher, \ + question_dialog from calibre.gui2.cover_flow import CoverFlowMixin from calibre.gui2.widgets import ProgressIndicator from calibre.gui2.update import UpdateMixin @@ -181,9 +182,8 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, # {{{ self.connect(self.donate_action, SIGNAL('triggered(bool)'), self.donate) self.connect(self.restore_action, SIGNAL('triggered()'), self.show_windows) - self.connect(self.system_tray_icon, - SIGNAL('activated(QSystemTrayIcon::ActivationReason)'), - self.system_tray_icon_activated) + self.system_tray_icon.activated.connect( + self.system_tray_icon_activated) ####################### Start spare job server ######################## @@ -250,7 +250,6 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, # {{{ self.keyboard_interrupt.connect(self.quit, type=Qt.QueuedConnection) - self.read_settings() self.finalize_layout() if self.tool_bar.showing_donate: @@ -301,6 +300,16 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, # {{{ else: self.show_windows() + @property + def is_minimized_to_tray(self): + return getattr(self, '__systray_minimized', False) + + def ask_a_yes_no_question(self, title, msg, **kwargs): + awu = kwargs.pop('ans_when_user_unavailable', True) + if self.is_minimized_to_tray: + return awu + return question_dialog(self, title, msg, **kwargs) + def hide_windows(self): for window in QApplication.topLevelWidgets(): if isinstance(window, (MainWindow, QDialog)) and \ @@ -428,31 +437,34 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, # {{{ def job_exception(self, job): if not hasattr(self, '_modeless_dialogs'): self._modeless_dialogs = [] + minz = self.is_minimized_to_tray if self.isVisible(): for x in list(self._modeless_dialogs): if not x.isVisible(): self._modeless_dialogs.remove(x) try: if 'calibre.ebooks.DRMError' in job.details: - d = error_dialog(self, _('Conversion Error'), - _('

Could not convert: %s

It is a ' - 'DRMed book. You must first remove the ' - 'DRM using third party tools.')%\ - (job.description.split(':')[-1], - 'http://bugs.calibre-ebook.com/wiki/DRM')) - d.setModal(False) - d.show() - self._modeless_dialogs.append(d) + if not minz: + d = error_dialog(self, _('Conversion Error'), + _('

Could not convert: %s

It is a ' + 'DRMed book. You must first remove the ' + 'DRM using third party tools.')%\ + (job.description.split(':')[-1], + 'http://bugs.calibre-ebook.com/wiki/DRM')) + d.setModal(False) + d.show() + self._modeless_dialogs.append(d) return if 'calibre.web.feeds.input.RecipeDisabled' in job.details: - msg = job.details - msg = msg[msg.find('calibre.web.feeds.input.RecipeDisabled:'):] - msg = msg.partition(':')[-1] - d = error_dialog(self, _('Recipe Disabled'), - '

%s

'%msg) - d.setModal(False) - d.show() - self._modeless_dialogs.append(d) + if not minz: + msg = job.details + msg = msg[msg.find('calibre.web.feeds.input.RecipeDisabled:'):] + msg = msg.partition(':')[-1] + d = error_dialog(self, _('Recipe Disabled'), + '

%s

'%msg) + d.setModal(False) + d.show() + self._modeless_dialogs.append(d) return except: pass @@ -462,12 +474,13 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, # {{{ prints(job.details, file=sys.stderr) except: pass - d = error_dialog(self, _('Conversion Error'), - _('Failed')+': '+unicode(job.description), - det_msg=job.details) - d.setModal(False) - d.show() - self._modeless_dialogs.append(d) + if not minz: + d = error_dialog(self, _('Conversion Error'), + _('Failed')+': '+unicode(job.description), + det_msg=job.details) + d.setModal(False) + d.show() + self._modeless_dialogs.append(d) def read_settings(self): geometry = config['main_window_geometry'] diff --git a/src/calibre/library/comments.py b/src/calibre/library/comments.py index 83eec89abe..00a6ef55ae 100644 --- a/src/calibre/library/comments.py +++ b/src/calibre/library/comments.py @@ -131,7 +131,8 @@ def comments_to_html(comments): def sanitize_comments_html(html): text = html2text(html) md = markdown.Markdown(safe_mode=True) - return md.convert(text) + cleansed = re.sub('\n+', '', md.convert(text)) + return cleansed def test(): for pat, val in [ diff --git a/src/calibre/library/server/base.py b/src/calibre/library/server/base.py index 29636c5659..711fcf03d8 100644 --- a/src/calibre/library/server/base.py +++ b/src/calibre/library/server/base.py @@ -147,7 +147,7 @@ class LibraryServer(ContentServer, MobileServer, XMLServer, OPDSServer, Cache, self.config['/'] = { 'tools.digest_auth.on' : True, 'tools.digest_auth.realm' : ( - _('Password to access your calibre library. Username is ') + 'Password to access your calibre library. Username is ' + opts.username.strip()), 'tools.digest_auth.users' : {opts.username.strip():opts.password.strip()}, } diff --git a/src/calibre/library/server/browse.py b/src/calibre/library/server/browse.py index 5609416273..db5c83689b 100644 --- a/src/calibre/library/server/browse.py +++ b/src/calibre/library/server/browse.py @@ -43,18 +43,33 @@ def render_book_list(ids, prefix, suffix=''): # {{{
''' - rpages = [] + pagelist_template = u'''\ +
+
    + {pages} +
+
+ ''' + rpages, lpages = [], [] for i, x in enumerate(pages): pg, pos = x ld = xml(json.dumps(pg), True) + start, end = pos+1, pos+len(pg) rpages.append(page_template.format(i, ld, xml(_('Loading, please wait')) + '…', - start=pos+1, end=pos+len(pg), prefix=prefix)) + start=start, end=end, prefix=prefix)) + lpages.append(' '*20 + (u'
  • ' + '{start} to {end}
  • ').format(start=start, end=end, + id='page%d'%i)) rpages = u'\n\n'.join(rpages) + lpages = u'\n'.join(lpages) + pagelist = pagelist_template.format(pages=lpages) templ = u'''\

    {0} {suffix}

    +
    {pagelist}
    {navbar}
    @@ -64,24 +79,31 @@ def render_book_list(ids, prefix, suffix=''): # {{{
    ''' - + gp_start = gp_end = '' + if len(pages) > 1: + gp_start = '' % \ + (_('Go to') + '…') + gp_end = '' navbar = u'''\ '''.format(first=_('First'), last=_('Last'), previous=_('Previous'), - next=_('Next'), num=num) + next=_('Next'), num=num, gp_start=gp_start, gp_end=gp_end) return templ.format(_('Browsing %d books')%num, suffix=suffix, - pages=rpages, navbar=navbar) + pages=rpages, navbar=navbar, pagelist=pagelist, + goto=xml(_('Go to'), True) + '…') # }}}