def run(self): """Run post-list directive.""" start = self.options.get('start') stop = self.options.get('stop') reverse = self.options.get('reverse', False) tags = self.options.get('tags') tags = [t.strip().lower() for t in tags.split(',')] if tags else [] categories = self.options.get('categories') categories = [c.strip().lower() for c in categories.split(',')] if categories else [] slugs = self.options.get('slugs') slugs = [s.strip() for s in slugs.split(',')] if slugs else [] show_all = self.options.get('all', False) lang = self.options.get('lang', utils.LocaleBorg().current_lang) template = self.options.get('template', 'post_list_directive.tmpl') sort = self.options.get('sort') output = _do_post_list(start, stop, reverse, tags, categories, slugs, show_all, lang, template, sort, state=self.state, site=self.site) self.state.document.settings.record_dependencies.add( "####MAGIC####TIMELINE") return [nodes.raw('', output, format='html')]
def run(self): """Run post-list directive.""" start = self.options.get('start') stop = self.options.get('stop') reverse = self.options.get('reverse', False) tags = self.options.get('tags') categories = self.options.get('categories') sections = self.options.get('sections') slugs = self.options.get('slugs') post_type = self.options.get('post_type') type = self.options.get('type', False) all = self.options.get('all', False) lang = self.options.get('lang', utils.LocaleBorg().current_lang) template = self.options.get('template', 'post_list_directive.tmpl') sort = self.options.get('sort') date = self.options.get('date') output, deps = _do_post_list(start, stop, reverse, tags, categories, sections, slugs, post_type, type, all, lang, template, sort, state=self.state, site=self.site, date=date) self.state.document.settings.record_dependencies.add("####MAGIC####TIMELINE") for d in deps: self.state.document.settings.record_dependencies.add(d) if output: return [nodes.raw('', output, format='html')] else: return []
def run(self): start = self.options.get('start') stop = self.options.get('stop') reverse = self.options.get('reverse', False) tags = self.options.get('tags') tags = [t.strip().lower() for t in tags.split(',')] if tags else [] slugs = self.options.get('slugs') slugs = [s.strip() for s in slugs.split(',')] if slugs else [] show_all = self.options.get('all', False) lang = self.options.get('lang', utils.LocaleBorg().current_lang) template = self.options.get('template', 'post_list_directive.tmpl') if self.site.invariant: # for testing purposes post_list_id = self.options.get('id', 'post_list_' + 'fixedvaluethatisnotauuid') else: post_list_id = self.options.get('id', 'post_list_' + uuid.uuid4().hex) posts = [] step = -1 if reverse is None else None if show_all is None: timeline = [p for p in self.site.timeline] else: timeline = [p for p in self.site.timeline if p.use_in_feeds] for post in timeline[start:stop:step]: if tags: cont = True for tag in tags: if tag in [t.lower() for t in post.tags]: cont = False if cont: continue if slugs: cont = True for slug in slugs: if slug == post.meta('slug'): cont = False if cont: continue posts += [post] if not posts: return [] template_data = { 'lang': lang, 'posts': posts, 'date_format': self.site.GLOBAL_CONTEXT.get('date_format'), 'post_list_id': post_list_id, } output = self.site.template_system.render_template( template, None, template_data) return [nodes.raw('', output, format='html')]
def set_site(self, site): self.site = site if self.site.config['DATE_FANCINESS'] == 0 and not self.site.config.get('BABEL_DATE_FORMAT') is None: babel_date_format = utils.TranslatableSetting( 'BABEL_DATE_FORMAT', self.site.config['BABEL_DATE_FORMAT'], self.site.config['TRANSLATIONS']) for lang in self.site.config['TRANSLATIONS']: try: self.site.config['DATE_FORMAT'][lang] = babel_date_format( lang) except KeyError: self.site.config['DATE_FORMAT'][lang] = 'medium' utils.LocaleBorg().add_handler(formatted_date_handler=self.babel_date_formatter) super(BabelDates, self).set_site(site)
def _build_month_post_list(self, lang): """Create a list of months.""" try: months = list(self.site.posts_per_month.keys()) months = sorted(months, reverse=True) month_list = [] for item in months: year, month = [int(part) for part in item.split('/')] month_name = utils.LocaleBorg().get_month_name(month, lang) month_page = Month_Page("{} {}".format(month_name, year), item) month_list.append(month_page) return month_list except KeyError: return None
def run(self): """Run post-list directive.""" start = self.options.get('start') stop = self.options.get('stop') reverse = self.options.get('reverse', False) tags = self.options.get('tags') require_all_tags = 'require_all_tags' in self.options categories = self.options.get('categories') sections = self.options.get('sections') slugs = self.options.get('slugs') post_type = self.options.get('post_type') type = self.options.get('type', False) lang = self.options.get('lang', utils.LocaleBorg().current_lang) template = self.options.get('template', 'post_list_directive.tmpl') sort = self.options.get('sort') date = self.options.get('date') filename = self.state.document.settings._nikola_source_path output, deps = self.site.plugin_manager.getPluginByName( 'post_list', 'ShortcodePlugin').plugin_object.handler(start, stop, reverse, tags, require_all_tags, categories, sections, slugs, post_type, type, lang, template, sort, state=self.state, site=self.site, date=date, filename=filename) self.state.document.settings.record_dependencies.add( "####MAGIC####TIMELINE") for d in deps: self.state.document.settings.record_dependencies.add(d) if output: return [nodes.raw('', output, format='html')] else: return []
def formatted_date(self, date_format, date=None): """Return the formatted date as unicode.""" return utils.LocaleBorg().formatted_date(date_format, date if date else self.date)
def run(self): start = self.options.get('start') stop = self.options.get('stop') reverse = self.options.get('reverse', False) tags = self.options.get('tags') tags = [t.strip().lower() for t in tags.split(',')] if tags else [] slugs = self.options.get('slugs') slugs = [s.strip() for s in slugs.split(',')] if slugs else [] show_all = self.options.get('all', False) lang = self.options.get('lang', utils.LocaleBorg().current_lang) template = self.options.get('template', 'post_list_directive.tmpl') sort = self.options.get('sort') if self.site.invariant: # for testing purposes post_list_id = self.options.get( 'id', 'post_list_' + 'fixedvaluethatisnotauuid') else: post_list_id = self.options.get('id', 'post_list_' + uuid.uuid4().hex) filtered_timeline = [] posts = [] step = -1 if reverse is None else None if show_all is None: timeline = [p for p in self.site.timeline] else: timeline = [p for p in self.site.timeline if p.use_in_feeds] for post in timeline: if tags: cont = True tags_lower = [t.lower() for t in post.tags] for tag in tags: if tag in tags_lower: cont = False if cont: continue filtered_timeline.append(post) if sort: filtered_timeline = natsorted( filtered_timeline, key=lambda post: post.meta[lang][sort]) for post in filtered_timeline[start:stop:step]: if slugs: cont = True for slug in slugs: if slug == post.meta('slug'): cont = False if cont: continue bp = post.translated_base_path(lang) if os.path.exists(bp): self.state.document.settings.record_dependencies.add(bp) posts += [post] if not posts: return [] template_data = { 'lang': lang, 'posts': posts, 'date_format': self.site.GLOBAL_CONTEXT.get('date_format'), 'post_list_id': post_list_id, } output = self.site.template_system.render_template( template, None, template_data) return [nodes.raw('', output, format='html')]
def generate_feed(self, lang, title, link, description, timeline, feed_url, output_name, primary_author=None): """Generate a feed and write it to file.""" utils.LocaleBorg().set_locale(lang) items = [] for post in timeline: item = { "id": post.guid(lang), "url": post.permalink(lang), "title": post.title(lang), "date_published": post.date.replace(microsecond=0).isoformat(), "date_modified": post.updated.replace(microsecond=0).isoformat(), "author": { "name": post.author(lang), "url": self.site.link("author", post.author(lang), lang) }, "tags": post.tags_for_language(lang), } if post.updated == post.date: del item["date_modified"] link = post.meta[lang].get('link') if link: item['external_url'] = link previewimage = post.meta[lang].get('previewimage') if previewimage: item['image'] = self.site.url_replacer(post.permalink(), previewimage, lang, 'absolute') if self.kw['feed_plain']: strip_html = True content_tag = "content_text" else: strip_html = False content_tag = "content_html" data = post.text(lang, self.kw['feed_teasers'], strip_html, True, True, self.kw['feed_links_append_query']) if feed_url is not None and data: # Copied from nikola.py # Massage the post's HTML (unless plain) if not strip_html: if self.kw["feed_previewimage"] and 'previewimage' in post.meta[lang] and post.meta[lang]['previewimage'] not in data: data = "<figure><img src=\"{}\"></figure> {}".format(post.meta[lang]['previewimage'], data) # FIXME: this is duplicated with code in Post.text() try: doc = lxml.html.document_fromstring(data) doc.rewrite_links(lambda dst: self.site.url_replacer(post.permalink(), dst, lang, 'absolute')) try: body = doc.body data = (body.text or '') + ''.join( [lxml.html.tostring(child, encoding='unicode') for child in body.iterchildren()]) except IndexError: # No body there, it happens sometimes data = '' except lxml.etree.ParserError as e: if str(e) == "Document is empty": data = "" else: # let other errors raise raise item[content_tag] = data items.append(item) if not primary_author: # Override for author pages primary_author = {"name": self.kw['blog_author'](lang)} feed = { "version": "https://jsonfeed.org/version/1", "user_comment": ("This feed allows you to read the posts from this " "site in any feed reader that supports the JSON " "Feed format. To add " "this feed to your reader, " "copy the following URL — " + feed_url + " — and add it your reader."), "title": title, "home_page_url": self.kw['site_url'], "feed_url": feed_url, "description": description, "author": primary_author, "items": items } utils.makedirs(os.path.dirname(output_name)) with io.open(output_name, 'w', encoding='utf-8') as fh: json.dump(feed, fh, ensure_ascii=False, indent=4)
def _do_post_list(start=None, stop=None, reverse=False, tags=None, categories=None, sections=None, slugs=None, post_type='post', type=False, all=False, lang=None, template='post_list_directive.tmpl', sort=None, id=None, data=None, state=None, site=None, date=None, filename=None, post=None): if lang is None: lang = utils.LocaleBorg().current_lang if site.invariant: # for testing purposes post_list_id = id or 'post_list_' + 'fixedvaluethatisnotauuid' else: post_list_id = id or 'post_list_' + uuid.uuid4().hex # Get post from filename if available if filename: self_post = site.post_per_input_file.get(filename) else: self_post = None if self_post: self_post.register_depfile("####MAGIC####TIMELINE", lang=lang) # If we get strings for start/stop, make them integers if start is not None: start = int(start) if stop is not None: stop = int(stop) # Parse tags/categories/sections/slugs (input is strings) tags = [t.strip().lower() for t in tags.split(',')] if tags else [] categories = [c.strip().lower() for c in categories.split(',')] if categories else [] sections = [s.strip().lower() for s in sections.split(',')] if sections else [] slugs = [s.strip() for s in slugs.split(',')] if slugs else [] filtered_timeline = [] posts = [] step = -1 if reverse is None else None if type is not False: post_type = type # TODO: remove in v8 if all is not False: timeline = [p for p in site.timeline] elif post_type == 'page' or post_type == 'pages': timeline = [p for p in site.timeline if not p.use_in_feeds] elif post_type == 'all': timeline = [p for p in site.timeline] else: # post timeline = [p for p in site.timeline if p.use_in_feeds] # TODO: replaces all, uncomment in v8 # if post_type == 'page' or post_type == 'pages': # timeline = [p for p in site.timeline if not p.use_in_feeds] # elif post_type == 'all': # timeline = [p for p in site.timeline] # else: # post # timeline = [p for p in site.timeline if p.use_in_feeds] if categories: timeline = [p for p in timeline if p.meta('category', lang=lang).lower() in categories] if sections: timeline = [p for p in timeline if p.section_name(lang).lower() in sections] for post in timeline: if tags: cont = True tags_lower = [t.lower() for t in post.tags] for tag in tags: if tag in tags_lower: cont = False if cont: continue filtered_timeline.append(post) if sort: filtered_timeline = natsort.natsorted(filtered_timeline, key=lambda post: post.meta[lang][sort], alg=natsort.ns.F | natsort.ns.IC) if date: filtered_timeline = [p for p in filtered_timeline if date_in_range(date, p.date)] for post in filtered_timeline[start:stop:step]: if slugs: cont = True for slug in slugs: if slug == post.meta('slug'): cont = False if cont: continue bp = post.translated_base_path(lang) if os.path.exists(bp) and state: state.document.settings.record_dependencies.add(bp) elif os.path.exists(bp) and self_post: self_post.register_depfile(bp, lang=lang) posts += [post] if not posts: return '', [] template_deps = site.template_system.template_deps(template) if state: # Register template as a dependency (Issue #2391) for d in template_deps: state.document.settings.record_dependencies.add(d) elif self_post: for d in template_deps: self_post.register_depfile(d, lang=lang) template_data = { 'lang': lang, 'posts': posts, # Need to provide str, not TranslatableSetting (Issue #2104) 'date_format': site.GLOBAL_CONTEXT.get('date_format')[lang], 'post_list_id': post_list_id, 'messages': site.MESSAGES, } output = site.template_system.render_template( template, None, template_data) return output, template_deps
def handler(self, start=None, stop=None, reverse=False, tags=None, require_all_tags=False, categories=None, sections=None, slugs=None, post_type='post', type=False, lang=None, template='post_list_directive.tmpl', sort=None, id=None, data=None, state=None, site=None, date=None, filename=None, post=None): """Generate HTML for post-list.""" if lang is None: lang = utils.LocaleBorg().current_lang if site.invariant: # for testing purposes post_list_id = id or 'post_list_' + 'fixedvaluethatisnotauuid' else: post_list_id = id or 'post_list_' + uuid.uuid4().hex # Get post from filename if available if filename: self_post = site.post_per_input_file.get(filename) else: self_post = None if self_post: self_post.register_depfile("####MAGIC####TIMELINE", lang=lang) # If we get strings for start/stop, make them integers if start is not None: start = int(start) if stop is not None: stop = int(stop) # Parse tags/categories/sections/slugs (input is strings) categories = [c.strip().lower() for c in categories.split(',')] if categories else [] sections = [s.strip().lower() for s in sections.split(',')] if sections else [] slugs = [s.strip() for s in slugs.split(',')] if slugs else [] filtered_timeline = [] posts = [] step = None if reverse is False else -1 if type is not False: post_type = type if post_type == 'page' or post_type == 'pages': timeline = [p for p in site.timeline if not p.use_in_feeds] elif post_type == 'all': timeline = [p for p in site.timeline] else: # post timeline = [p for p in site.timeline if p.use_in_feeds] # self_post should be removed from timeline because this is redundant timeline = [p for p in timeline if p.source_path != filename] if categories: timeline = [p for p in timeline if p.meta('category', lang=lang).lower() in categories] if sections: timeline = [p for p in timeline if p.section_name(lang).lower() in sections] if tags: tags = {t.strip().lower() for t in tags.split(',')} if require_all_tags: compare = set.issubset else: compare = operator.and_ for post in timeline: post_tags = {t.lower() for t in post.tags} if compare(tags, post_tags): filtered_timeline.append(post) else: filtered_timeline = timeline if sort: filtered_timeline = natsort.natsorted(filtered_timeline, key=lambda post: post.meta[lang][sort], alg=natsort.ns.F | natsort.ns.IC) if date: _now = utils.current_time() filtered_timeline = [p for p in filtered_timeline if date_in_range(utils.html_unescape(date), p.date, now=_now)] for post in filtered_timeline[start:stop:step]: if slugs: cont = True for slug in slugs: if slug == post.meta('slug'): cont = False if cont: continue bp = post.translated_base_path(lang) if os.path.exists(bp) and state: state.document.settings.record_dependencies.add(bp) elif os.path.exists(bp) and self_post: self_post.register_depfile(bp, lang=lang) posts += [post] if not posts: return '', [] template_deps = site.template_system.template_deps(template) if state: # Register template as a dependency (Issue #2391) for d in template_deps: state.document.settings.record_dependencies.add(d) elif self_post: for d in template_deps: self_post.register_depfile(d, lang=lang) template_data = { 'lang': lang, 'posts': posts, # Need to provide str, not TranslatableSetting (Issue #2104) 'date_format': site.GLOBAL_CONTEXT.get('date_format')[lang], 'post_list_id': post_list_id, 'messages': site.MESSAGES, '_link': site.link, } output = site.template_system.render_template( template, None, template_data) return output, template_deps
def _do_post_list(start=None, stop=None, reverse=False, tags=None, categories=None, slugs=None, show_all=False, lang=None, template='post_list_directive.tmpl', sort=None, id=None, data=None, state=None, site=None): if lang is None: lang = utils.LocaleBorg().current_lang if site.invariant: # for testing purposes post_list_id = id or 'post_list_' + 'fixedvaluethatisnotauuid' else: post_list_id = id or 'post_list_' + uuid.uuid4().hex filtered_timeline = [] posts = [] step = -1 if reverse is None else None if show_all is None: timeline = [p for p in site.timeline] else: timeline = [p for p in site.timeline if p.use_in_feeds] if categories: timeline = [p for p in timeline if p.meta('category', lang=lang).lower() in categories] for post in timeline: if tags: cont = True tags_lower = [t.lower() for t in post.tags] for tag in tags: if tag in tags_lower: cont = False if cont: continue filtered_timeline.append(post) if sort: filtered_timeline = natsort.natsorted(filtered_timeline, key=lambda post: post.meta[lang][sort], alg=natsort.ns.F | natsort.ns.IC) for post in filtered_timeline[start:stop:step]: if slugs: cont = True for slug in slugs: if slug == post.meta('slug'): cont = False if cont: continue bp = post.translated_base_path(lang) if os.path.exists(bp) and state: state.document.settings.record_dependencies.add(bp) posts += [post] if not posts: return [] template_data = { 'lang': lang, 'posts': posts, # Need to provide str, not TranslatableSetting (Issue #2104) 'date_format': site.GLOBAL_CONTEXT.get('date_format')[lang], 'post_list_id': post_list_id, 'messages': site.MESSAGES, } output = site.template_system.render_template( template, None, template_data) return output
def formatted_date(self, date_format): """Return the formatted localized date.""" return utils.LocaleBorg().formatted_date(date_format, self.date_localized)