5 Commits
v0.9.0 ... main

Author SHA1 Message Date
relikd
19bee043fc chore: bump to v0.9.2 2022-12-20 02:50:33 +01:00
relikd
6d7456a85b docs: add example project 2022-12-20 02:49:31 +01:00
relikd
a9ce2a2e9a feat: update groupby to v0.9.8 2022-12-20 02:49:19 +01:00
relikd
fea4e182a5 known issue fixed, update readme 2022-04-13 23:02:03 +02:00
relikd
81bb61eb0b update makefile + bump groupby to v0.9.6 2022-04-13 22:29:56 +02:00
12 changed files with 122 additions and 54 deletions

2
.gitignore vendored
View File

@@ -1,5 +1,5 @@
.DS_Store
/dist-env/
/env-publish/
__pycache__/
*.py[cod]

View File

@@ -1,21 +1,17 @@
.PHONY: help
help:
@echo 'commands:'
@echo ' dist'
dist-env:
@echo Creating virtual environment...
@python3 -m venv 'dist-env'
@source dist-env/bin/activate && pip install twine
.PHONY: dist
dist: dist-env
dist: setup.py lektor_inlinetags.py
[ -z "$${VIRTUAL_ENV}" ] # you can not do this inside a virtual environment.
rm -rf dist
@echo Building...
python3 setup.py sdist bdist_wheel
@echo
rm -rf ./*.egg-info/ ./build/ MANIFEST
env-publish:
@echo Creating virtual environment...
@python3 -m venv 'env-publish'
@source env-publish/bin/activate && pip install twine
.PHONY: publish
publish: dist env-publish
[ -z "$${VIRTUAL_ENV}" ] # you can not do this inside a virtual environment.
@echo Publishing...
@echo "\033[0;31mEnter your PyPI token:\033[0m"
@source dist-env/bin/activate && export TWINE_USERNAME='__token__' && twine upload dist/*
@echo "\033[0;31mEnter PyPI token in password prompt:\033[0m"
@source env-publish/bin/activate && export TWINE_USERNAME='__token__' && twine upload dist/*

View File

@@ -7,14 +7,8 @@ Of course, you can configure a different matching pattern, e.g., instead of the
This plugin is based on the [lektor-groupby](https://github.com/relikd/lektor-groupby-plugin) plugin.
All configuration options from groupby can be used (including multiple attribute names).
### Known issues
In rare cases, clicking on "Save Changes" will not replace the tags of the current page.
It happens because the page is built concurrently (race condition).
This affects only the currently edited page and only the inline replacements (the tags page is updated just fine).
If this occurs to you, simply edit and save the page again.
Further, you can access the tags of a page with the filter `|vgroups(key1, key2, recursive=False)` where key is `0..N` attribute keys.
If no key is provided, all attributes will be returned otherwise only matching attribute keys.
### Example config file
@@ -37,15 +31,15 @@ In your plugin config (`configs/inlinetags.ini`):
```ini
[inlinetags]
root = /
slug = "tag/{}/index.html".format(this.key)
slug = tag/{key}/
template = tag-page.html
[inlinetags.pattern]
match = {{([^}]{1,32})}}
replace = <a href="/tag/{key}/">{name}</a>
replace = <a class="tag" href="{url}">{name}</a>
[inlinetags.fields]
title = "Tagged: " ~ this.group
title = "Tagged: " ~ this.key_obj
[inlinetags.key_map]
C# = c-sharp

View File

@@ -0,0 +1,5 @@
[project]
name = Inlinetags Example
[packages]
lektor-inlinetags = 0.9.2

7
example/Makefile Normal file
View File

@@ -0,0 +1,7 @@
.PHONY: server clean plugins
server:
lektor server
clean:
lektor clean --yes -v
plugins:
lektor plugins flush-cache && lektor plugins list

View File

@@ -0,0 +1,23 @@
[inlinetags]
root = /
slug = tag/{key}/
template = tag-page.html
[inlinetags.pattern]
match = {{([^}]{1,32})}}
replace = <a class="tag" href="{url}">{name}</a>
[inlinetags.fields]
title = "Tagged: " ~ this.key_obj
[inlinetags.key_map]
C# = c-sharp
[inlinetags_hidden]
slug = hidden-tag/{key}/
template = tag-page.html
[inlinetags_hidden.pattern]
match = {{([^}]{1,32})}}
replace = {name}

View File

@@ -0,0 +1,3 @@
title: Use Inlinetags in {{title}}!
---
body: This is a {{demo}} {{demo}} website that shows how to use {{Lektor}} with inline {{tags}}. Test {{C#}}.

13
example/models/page.ini Normal file
View File

@@ -0,0 +1,13 @@
[model]
name = Page
label = {{ this.title }}
[fields.title]
label = Title
type = string
inlinetags_hidden = true
[fields.body]
label = Body
type = markdown
inlinetags = true

View File

@@ -0,0 +1,21 @@
<!doctype html>
<meta charset="utf-8">
<title>Inlinetags</title>
<style type="text/css">
main { margin: 1em; }
footer { padding: 1em; background: #DDD; }
</style>
<body>
<main>
{# Using "|safe" to allow clickable links in title #}
<h2>{{ this.title|safe }}</h2>
{% block body %}{{ this.body }}{% endblock %}
</main>
<footer>
<a href="/">Root</a>,
Tags:
{%- for x in this|vgroups(recursive=True, order_by='key_obj') %}
<a href="{{ x|url }}">&lt;{{x.key_obj}}&gt;</a>
{%- endfor %}
</footer>
</body>

View File

@@ -0,0 +1,10 @@
{% extends "page.html" %}
{% block body %}
<p>Key: <b>{{this.key}}</b> | Object: <b>{{this.key_obj}}</b></p>
Page with <b>{{this.children.count()}}</b> tag(s):
<ul>
{%- for child in this.children|unique %}
<li><a href="{{child|url}}">{{child.title}}</a></li>
{%- endfor %}
</ul>
{% endblock %}

View File

@@ -1,34 +1,26 @@
from lektor.context import get_ctx
from lektor.db import Record # typing
from lektor.markdown import Markup
from lektor.pluginsystem import Plugin, IniFile # subclass
from lektor.sourceobj import VirtualSourceObject as VObj # typing
from typing import Set, Dict, Any, Iterator, Generator
from lektor.markdown import Markup # isinstance
from lektor.pluginsystem import Plugin # subclass
import re
from lektor_groupby.groupby import GroupBy # typing
from lektor_groupby.util import report_config_error
from lektor_groupby.watcher import GroupByCallbackArgs # typing
from typing import TYPE_CHECKING, Set, Dict, Any, Generator
if TYPE_CHECKING:
from lektor.pluginsystem import IniFile
from lektor_groupby import GroupBy, GroupByCallbackArgs
class InlineTagsPlugin(Plugin):
name = 'inlinetags'
description = 'Auto-detect and reference tags inside written text.'
def on_setup_env(self, **extra: Any) -> None:
def _fn(record: Record, *, recursive: bool = False) -> Iterator[VObj]:
fn = self.env.jinja_env.filters['vgroups']
yield from fn(record, *self.config_keys, recursive=recursive)
self.env.jinja_env.filters.update(inlinetags=_fn)
def on_process_template_context(self, context: Dict, **extra: Any) -> None:
if hasattr(context.get('this'), '_inlinetag_modified'):
ctx = get_ctx()
if ctx:
ctx.record_dependency(self.config_filename)
def on_groupby_before_build_all(self, groupby: GroupBy, **ex: Any) -> None:
def on_groupby_before_build_all(self, groupby: 'GroupBy', **extra: Any) \
-> None:
''' lektor-groupby entry point. '''
self.config_keys = set() # type: Set[str]
config = self.get_config()
for sect in config.sections():
@@ -37,20 +29,23 @@ class InlineTagsPlugin(Plugin):
if self._add(sect, config, groupby):
self.config_keys.add(sect)
def _add(self, sect_key: str, config: IniFile, groupby: GroupBy) -> bool:
def _add(self, sect_key: str, config: 'IniFile', groupby: 'GroupBy') \
-> bool:
''' Parse config section and add callback. Return True on success. '''
_pattern = config.section_as_dict(sect_key + '.pattern')
regex_str = _pattern.get('match', r'{{([^}]{1,32})}}') # type: str
tag_replace = _pattern.get('replace', '{name}') # type: str
try:
regex = re.compile(regex_str)
except Exception as e:
report_config_error(sect_key, 'pattern.match', regex_str, e)
return False
raise ValueError(
'Invalid regex patter [{}.{}] = "{}" Error: {}'.format(
sect_key, 'pattern.match', regex_str, repr(e)))
watcher = groupby.add_watcher(sect_key, config)
watcher = groupby.add_watcher(sect_key, config, pre_build=True)
@watcher.grouping()
def _inlinetag(args: GroupByCallbackArgs) -> Generator[str, str, None]:
def _fn(args: 'GroupByCallbackArgs') -> Generator[str, str, None]:
arr = args.field if isinstance(args.field, list) else [args.field]
_tags = {} # type: Dict[str, str]
for obj in arr:
@@ -59,14 +54,15 @@ class InlineTagsPlugin(Plugin):
if isinstance(obj, str) and str:
for match in regex.finditer(obj):
name = match.group(1)
_tags[name] = yield name
vobj = yield name
_tags[name] = vobj.url_path
# ignore other types (int, float, date, url, undefined)
# replace inline-tags with hyperlink
if _tags:
def _repl_tags(match: re.Match) -> str:
name = match.group(1)
return tag_replace.format(key=_tags[name], name=name)
return tag_replace.format(url=_tags[name], name=name)
args.record._inlinetag_modified = True
# get field value

View File

@@ -6,7 +6,7 @@ with open('README.md') as fp:
setup(
name='lektor-inlinetags',
py_modules=['lektor_inlinetags'],
install_requires=['lektor-groupby>=0.9.5'],
install_requires=['lektor-groupby==0.9.8'],
entry_points={
'lektor.plugins': [
'inlinetags = lektor_inlinetags:InlineTagsPlugin',
@@ -14,7 +14,7 @@ setup(
},
author='relikd',
url='https://github.com/relikd/lektor-inlinetags-plugin',
version='0.9',
version='0.9.2',
description='Auto-detect and reference tags inside written text.',
long_description=longdesc,
long_description_content_type="text/markdown",