Merge remote-tracking branch 'refs/remotes/origin/master' into feature/documentation

This commit is contained in:
Elias Zeitfogel 2015-12-26 11:01:54 +01:00
commit 2bcabe1a4e
82 changed files with 908 additions and 224 deletions

View File

@ -3,10 +3,17 @@ python: 2.7
install: install:
- "pip install -U pip" - "pip install -U pip"
- "pip install git+https://github.com/lektor/lektor#egg=Lektor" - "pip install git+https://github.com/lektor/lektor#egg=Lektor"
script: "lektor build && lektor deploy production" script:
- "lektor build"
- "test \"$TRAVIS_PULL_REQUEST\" == \"false\" && test \"$TRAVIS_BRANCH\" == \"master\" && lektor deploy production"
cache: cache:
directories: directories:
- $HOME/.cache/pip - $HOME/.cache/pip
- $HOME/.cache/lektor/builds - $HOME/.cache/lektor/builds
addons: addons:
ssh_known_hosts: flow.srv.pocoo.org ssh_known_hosts: flow.srv.pocoo.org
notifications:
webhooks:
urls:
- https://webhooks.gitter.im/e/f0c538cdfc9883f81e34

View File

@ -12,3 +12,5 @@ default = yes
[packages] [packages]
lektor-webpack-support = 0.1 lektor-webpack-support = 0.1
lektor-disqus-comments = 0.1 lektor-disqus-comments = 0.1
lektor-markdown-header-anchors = 0.1
lektor-markdown-highlighter = 0.1

View File

@ -24,6 +24,7 @@ if 1:
import json import json
import urllib import urllib
import tempfile import tempfile
import shutil
from subprocess import Popen from subprocess import Popen
sys.stdin = open('/dev/tty', 'r') sys.stdin = open('/dev/tty', 'r')
@ -59,6 +60,32 @@ if 1:
os.path.dirname(path), 'lib', 'lektor') os.path.dirname(path), 'lib', 'lektor')
None, None None, None
def get_confirmation():
while 1:
input = raw_input('Continue? [Yn] ').lower().strip()
if input in ('', 'y'):
break
elif input == 'n':
print
print 'Aborted!'
sys.exit()
def wipe_installation(lib_dir, symlink_path):
if os.path.lexists(symlink_path):
os.remove(symlink_path)
if os.path.exists(lib_dir):
shutil.rmtree(lib_dir, ignore_errors=True)
def check_installation(lib_dir, bin_dir):
symlink_path = os.path.join(bin_dir, 'lektor')
if os.path.exists(lib_dir) or os.path.lexists(symlink_path):
print ' Lektor seems to be installed already.'
print ' Continuing will wipe %s and remove %s' % (lib_dir, symlink_path)
print
get_confirmation()
print
wipe_installation(lib_dir, symlink_path)
def fail(message): def fail(message):
print 'Error: %s' % message print 'Error: %s' % message
sys.exit(1) sys.exit(1)
@ -67,6 +94,7 @@ if 1:
t = tempfile.mkdtemp() t = tempfile.mkdtemp()
Popen('curl -sf "%s" | tar -xzf - --strip-components=1' % Popen('curl -sf "%s" | tar -xzf - --strip-components=1' %
virtualenv_url, shell=True, cwd=t).wait() virtualenv_url, shell=True, cwd=t).wait()
try: try:
os.makedirs(lib_dir) os.makedirs(lib_dir)
except OSError: except OSError:
@ -78,6 +106,7 @@ if 1:
os.path.join(bin_dir, 'lektor')) os.path.join(bin_dir, 'lektor'))
def main(): def main():
print
print 'Welcome to Lektor' print 'Welcome to Lektor'
print print
print 'This script will install Lektor on your computer.' print 'This script will install Lektor on your computer.'
@ -92,17 +121,14 @@ if 1:
if bin_dir is None or lib_dir is None: if bin_dir is None or lib_dir is None:
fail('Could not determine installation location for Lektor.') fail('Could not determine installation location for Lektor.')
check_installation(lib_dir, bin_dir)
print 'Installing at:'
print ' bin: %s' % bin_dir print ' bin: %s' % bin_dir
print ' app: %s' % lib_dir print ' app: %s' % lib_dir
print print
while 1: get_confirmation()
input = raw_input('Continue? [Yn] ').lower().strip()
if input in ('', 'y'):
break
elif input == 'n':
print 'Aborted!'
sys.exit()
for url in json.load(urllib.urlopen(VENV_URL))['urls']: for url in json.load(urllib.urlopen(VENV_URL))['urls']:
if url['python_version'] == 'source': if url['python_version'] == 'source':

View File

@ -1,4 +1,4 @@
!function(t){function e(i){if(n[i])return n[i].exports;var o=n[i]={exports:{},id:i,loaded:!1};return t[i].call(o.exports,o,o.exports,e),o.loaded=!0,o.exports}var n={};return e.m=t,e.c=n,e.p="",e(0)}([function(t,e,n){(function(t){"use strict";function e(t){if(document.body.createTextRange){var e=document.body.createTextRange();e.moveToElementText(t),e.select()}else if(window.getSelection){var n=window.getSelection(),e=document.createRange();e.selectNodeContents(t),n.removeAllRanges(),n.addRange(e)}}function i(){var e=t(".download-btn");e.length<=0||(e.hide(),t.ajax({method:"GET",url:"https://api.github.com/repos/lektor/lektor/releases",crossDomain:!0}).then(function(t){r(e.toArray(),t)},function(){e.show()}))}function o(t){var e=null,n=null;if(navigator.platform.match(/^mac/i)&&(e=/\.dmg$/,n="For OSX 10.9 and later."),null!=e)for(var i=0;i<t.length;i++)if(t[i].name.match(e))return{url:t[i].browser_download_url,note:n};return null}function r(e,n){var i=n[0].tag_name,r="/downloads/",s=o(n[0].assets);e.forEach(function(e){var n=t('<div class="note"></div>').appendTo(e),o=t("a",e);s?(o.attr("href",s.url),n.append(t("<span></span>").text(s.note+" ")),n.append(t("<a>Other platforms</a>").attr("href",r))):o.attr("href",r),o.append(t('<span class="version"></span>').text(i)),t(e).fadeIn("slow")})}function s(){var n=t(".install-row pre");n.length>0&&n.on("dblclick",function(){e(this)})}function a(){var e=t(".google-custom-search");if(0!=e.length){var n="012722186170730423054:utwznhnrrmi",i=document.createElement("script");i.type="text/javascript",i.async=!0,i.src=("https:"==document.location.protocol?"https:":"http:")+"//cse.google.com/cse.js?cx="+n;var o=document.getElementsByTagName("script")[0];o.parentNode.insertBefore(i,o),t('\n <gcse:searchresults-only linktarget="_parent"></gcse:searchresults-only>\n ').appendTo(e),t('\n <div style="display: none">\n <div id="base_webResult">\n <div class="gs-webResult gs-result"\n data-vars="{\n longUrl: function() {\n var i = unescapedUrl.indexOf(visibleUrl);\n return i < 1 ? visibleUrl : unescapedUrl.substring(i);\n },\n processSearchTitle: function(title) {\n return title.split(\' | \').slice(0, -2).join(\' | \') || \'Documentation\';\n }\n }">\n <div class="gs-title">\n <a class="gs-title" data-attr="{href:unescapedUrl, target:target}"\n data-body="html(processSearchTitle(title))"></a>\n </div>\n <div class="gs-visibleUrl gs-visibleUrl-long" data-body="longUrl()"></div>\n <div class="gs-snippet" data-body="html(content)"></div>\n </div>\n </div>\n </div>\n ').appendTo(e);var r=c.parse(location.search);r.q&&t('input[name="q"]',e).val(r.q)}}function l(){navigator.appVersion.indexOf("Win")>=0&&t(".hide-for-windows").hide()}n(2);var c=n(15);t(function(){i(),s(),a(),l()})}).call(e,n(1))},function(t,e,n){var i,o;/*! !function(t){function e(i){if(n[i])return n[i].exports;var o=n[i]={exports:{},id:i,loaded:!1};return t[i].call(o.exports,o,o.exports,e),o.loaded=!0,o.exports}var n={};return e.m=t,e.c=n,e.p="",e(0)}([function(t,e,n){(function(t){"use strict";function e(t){if(document.body.createTextRange){var e=document.body.createTextRange();e.moveToElementText(t),e.select()}else if(window.getSelection){var n=window.getSelection(),e=document.createRange();e.selectNodeContents(t),n.removeAllRanges(),n.addRange(e)}}function i(){function e(){var o=n[i++];o&&(window.setTimeout(e,200),t(o).fadeIn())}var n=t(".badges li").hide();if(!(n.length<=0)){var i=0;window.setTimeout(function(){e()},1e3)}}function o(){var e=t(".download-btn");e.length<=0||(e.hide(),t.ajax({method:"GET",url:"https://api.github.com/repos/lektor/lektor/releases",crossDomain:!0}).then(function(t){s(e.toArray(),t)},function(){e.show()}))}function r(t){var e=null,n=null;if(navigator.platform.match(/^mac/i)&&(e=/\.dmg$/,n="For OSX 10.9 and later."),null!=e)for(var i=0;i<t.length;i++)if(t[i].name.match(e))return{url:t[i].browser_download_url,note:n};return null}function s(e,n){var i=n[0].tag_name,o="/downloads/",s=r(n[0].assets);e.forEach(function(e){var n=t('<div class="note"></div>').appendTo(e),r=t("a",e);s?(r.attr("href",s.url),n.append(t("<span></span>").text(s.note+" ")),n.append(t("<a>Other platforms</a>").attr("href",o))):r.attr("href",o),r.append(t('<span class="version"></span>').text(i)),t(e).fadeIn("slow")})}function a(){var n=t(".install-row pre");n.length>0&&n.on("dblclick",function(){e(this)})}function l(){var e=t(".google-custom-search");if(0!=e.length){var n="012722186170730423054:utwznhnrrmi",i=document.createElement("script");i.type="text/javascript",i.async=!0,i.src=("https:"==document.location.protocol?"https:":"http:")+"//cse.google.com/cse.js?cx="+n;var o=document.getElementsByTagName("script")[0];o.parentNode.insertBefore(i,o),t('\n <gcse:searchresults-only linktarget="_parent"></gcse:searchresults-only>\n ').appendTo(e),t('\n <div style="display: none">\n <div id="base_webResult">\n <div class="gs-webResult gs-result"\n data-vars="{\n longUrl: function() {\n var i = unescapedUrl.indexOf(visibleUrl);\n return i < 1 ? visibleUrl : unescapedUrl.substring(i);\n },\n processSearchTitle: function(title) {\n return title.split(\' | \').slice(0, -2).join(\' | \') || \'Documentation\';\n }\n }">\n <div class="gs-title">\n <a class="gs-title" data-attr="{href:unescapedUrl, target:target}"\n data-body="html(processSearchTitle(title))"></a>\n </div>\n <div class="gs-visibleUrl gs-visibleUrl-long" data-body="longUrl()"></div>\n <div class="gs-snippet" data-body="html(content)"></div>\n </div>\n </div>\n </div>\n ').appendTo(e);var r=u.parse(location.search);r.q&&t('input[name="q"]',e).val(r.q)}}function c(){navigator.appVersion.indexOf("Win")>=0&&t(".hide-for-windows").hide()}n(2);var u=n(15);t(function(){i(),o(),a(),l(),c()})}).call(e,n(1))},function(t,e,n){var i,o;/*!
* jQuery JavaScript Library v2.1.4 * jQuery JavaScript Library v2.1.4
* http://jquery.com/ * http://jquery.com/
* *

View File

@ -1 +1 @@
{"version":3,"file":"app.js","sources":["webpack:///app.js","webpack:///"],"mappings":"AAAA;;;;;;;;;;;;;AC+LA;;;;;;;;;;AAqiBA;AAqpHA;AAkgIA;AAg3EA","sourceRoot":""} {"version":3,"file":"app.js","sources":["webpack:///app.js","webpack:///"],"mappings":"AAAA;;;;;;;;;;;;;ACuNA;;;;;;;;;;AAqiBA;AAqpHA;AAkgIA;AAg3EA","sourceRoot":""}

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 226 KiB

After

Width:  |  Height:  |  Size: 211 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 279 KiB

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 415 KiB

After

Width:  |  Height:  |  Size: 368 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 241 KiB

After

Width:  |  Height:  |  Size: 158 KiB

View File

@ -0,0 +1,37 @@
title: Lektor Loves Travis-CI and GitHub Pages
---
summary:
Read about how to use Lektor with Travis-CI and GitHub Pages.
---
pub_date: 2015-12-23
---
author: Armin Ronacher
---
twitter_handle: mitsuhiko
---
body:
#### banner ####
image: header.jpg
----
height: 500
#### text-block ####
text:
Open Source projects need websites, that's a given, and one of the most popular
ways to host them these days is [GitHub Pages :ext](https://pages.github.com/).
It's a free service provided by [GitHub :ext](https://github.com/) which allows
hosts a git repository as a website on a subdomain of `github.io`.
Wouldn't it be nice if you could easily host Lektor projects on there? Turns
out you can with the help of [Travis-CI :ext](https://travis-ci.org/). Because
Lektor has built-in support for deploying to GitHub Pages pairing up the three
is a breeze.
We [created a guide :ref](../../../../docs/deployment/travisci/) and also recorded
a screencast that goes with it:
<iframe width="100%" height=410 frameborder="0" allowfullscreen="allowfullscreen"
src="https://www.youtube.com/embed/3pj_EyZIL5A?autoplay=0&fs=1">
</iframe>

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 337 KiB

After

Width:  |  Height:  |  Size: 314 KiB

View File

@ -9,8 +9,6 @@ image: header.jpg
---- ----
height: 500 height: 500
---- ----
class: dark
----
contents: contents:
<div class="container lektor-intro"> <div class="container lektor-intro">
@ -37,6 +35,9 @@ contents:
data-count-api="/repos/lektor/lektor#stargazers_count" data-count-api="/repos/lektor/lektor#stargazers_count"
data-count-aria-label="# stargazers on GitHub" data-count-aria-label="# stargazers on GitHub"
aria-label="Star lektor/lektor on GitHub">Star</a> aria-label="Star lektor/lektor on GitHub">Star</a>
<li><a href="https://gitter.im/lektor/lektor"><img
src="https://badges.gitter.im/lektor/lektor.svg"
alt="Join the chat at https://gitter.im/lektor/lektor"></a>
</ul> </ul>
</div> </div>
</div> </div>
@ -74,7 +75,7 @@ text:
system is written in Python and provides a documented API to extend it and system is written in Python and provides a documented API to extend it and
integrate into other apps. integrate into other apps.
* <i class="feature-circle fa fa-language"></i> **Multilingual** We can * <i class="feature-circle fa fa-language"></i> **Multilingual** We can
speak multiple languages and allows you to easily create localized websites. speak multiple languages and allow you to easily create localized websites.
---- ----
class: two-column-list class: two-column-list
#### slideshow #### #### slideshow ####

View File

@ -0,0 +1,32 @@
title: is_discoverable
---
summary: Indicates that a record can be discovered via .children
---
type: property
---
version_added: 2.0
---
body:
Records can be discoverable or non discoverable. This is controlled by the
`_discoverable` system field which defaults to `yes. This property can quickly
check if a record is considered non-discoverable by Lektor or not. In
particular a hidden record is also considered undiscoverable.
Undiscoverable records can be queried and final pages will be built but they
are excempt from queries of the record. This is useful for pages that should
be built but not show up yet on overview pages. For instance this can be used
to implement drafts of blog posts or similar things.
This property is implemented on the level of source objects to make it
possible to use this API in all cases. The default implementation of
source objects will always return `true` for discoverability checks.
## Example
```html+jinja
{% set downloads = site.get('/downloads') %}
{% if downloads.is_discoverable %}
<p><a href="{{ downloads|url }}">Go to downloads</a>
{% endif %}
```

View File

@ -0,0 +1,13 @@
title: is_undiscoverable
---
summary: The inverse of is_discoverable.
---
type: property
---
version_added: 2.0
---
body:
This works like [is_discoverable :ref](../is-discoverable/) but the other
way around. It just exists for consistency and to make checks look a little
bit nicer in some places.

View File

@ -10,8 +10,9 @@ body:
This controls how the query should behave with regards to hidden records. This controls how the query should behave with regards to hidden records.
A query created from the [children :ref](../../record/children/) attribute of A query created from the [children :ref](../../record/children/) attribute of
a record will not include hidden records by default. The opposite is true a record will not include hidden records (or undiscoverable) by default. The
for queries created from the [query :ref](../../pad/query/) method of the pad. opposite is true for queries created from the [query :ref](../../pad/query/)
method of the pad.
The parameter can be set to `True` to include hidden or `False` to exclude The parameter can be set to `True` to include hidden or `False` to exclude
hidden records. hidden records.

View File

@ -0,0 +1,31 @@
title: include_undiscoverable
---
signature: value
---
summary: Controls what happens to records that are not discoverable.
---
type: method
---
version_added: 2.0
---
body:
This controls how the query should behave with regards to undiscoverable
records. A query (either created from the [children :ref](../../record/children/)
attribute or the [query :ref](../../pad/query/) method of the pad) will not
include undiscoverable records by default.
If undiscoverable records should included this method needs to be used.
Set it to `True` to include hidden or `False` to exclude them (default).
## Example
Here a basic example of how to filter something in a template:
```html+jinja
<ul>
{% for item in this.children.include_undiscoverable(true) %}
<li>{{ item.title }}
{% endfor %}
</ul>
```

View File

@ -0,0 +1,22 @@
title: []
---
summary: Looks up a field from the type.
---
type: operator
---
body:
The “get-item” operator is used to look up a field from a record. Within
templates attribute access automatically falls back to this operator which
is why you can typically access `foo.bar` instead of `foo['bar']` unless a
conflict with a record property exists.
All available fields can be accessed this way (model defined fields as well
as system fields which are prefixed by an underscore).
## Example
```python
for child in this.children:
print 'ID: %s' % child['_id']
```

View File

@ -16,7 +16,7 @@ overview page.
The following attributes exist on the pagination object: The following attributes exist on the pagination object:
| Attribute | Description | Attribute | Description
| ----------- | ------------ | ------------ | ------------
| `current` | The current record | `current` | The current record
| `prev` | The record for the last page (might be `None`) | `prev` | The record for the last page (might be `None`)
| `next` | The record for the net page (might be `None`) | `next` | The record for the net page (might be `None`)
@ -26,6 +26,12 @@ The following attributes exist on the pagination object:
| `has_prev` | `True` if a previous page exists | `has_prev` | `True` if a previous page exists
| `has_next` | `True` if a next page exists | `has_next` | `True` if a next page exists
| `items` | The query that resolves to the children of the current page. | `items` | The query that resolves to the children of the current page.
| `for_page()` | Returns the record for a different page.
The `for_page()` function accepts a page number and returns the record for
the other page.
!! *Changed in Lektor 2.0:* The `for_page()` method was added.
## Item Query Example ## Item Query Example

View File

@ -0,0 +1,11 @@
title: _alt
---
summary: The alt for this record.
---
type: sysfield
---
body:
This field points to the [Alternative :ref](../../../../content/alts/) of
the page. This should be considered as an internal field that is exposed
through the [alt :ref](../../obj/alt/) source object property instead.

View File

@ -0,0 +1,14 @@
title: _attachment_type
---
summary: An indication of the attachment type.
---
type: sysfield
---
body:
This indicates the type of the attachment. Currently only a small set of
attachments is detected. The most useful attachment type is `image` which
identifies images. The attachments are detected by the file extension.
!!!! This feature in many ways does not entirely work as you would expect
and should be taken is something that will improve in future versions.

View File

@ -0,0 +1,13 @@
title: System Fields
---
summary: The complete list of system fields in Lektor
---
body:
All records have a few system fields available in addition to the fields
defined by the data model. These fields are always there and control internal
behavior in Lektor. They are prefixed by an underscore to separate them
from the fields a model defines.
Many system fields are hidden from the admin panel but some can be changed
there (`_template`, `_hidden`, and a few others).

View File

@ -0,0 +1,20 @@
title: _discoverable
---
summary: Controls if this page is picked up by collection queries by default.
---
type: sysfield
---
version_added: 2.0
---
body:
By default any non hidden page is returned from `.children` on iteration. This
field can be set to `no` to hide a page from such default queries. This
implicitly hides a page for most template operations but Lektor will still
build it. This for instance is very useful for draft blog posts. If a post is
set to not being discoverable it will be hidden from the blog index without
further custom template code, but someone who knows the URL can still find it.
This is also particularly useful to hide special pages such as `sitemap.xml`
which would otherwise cause problems because generic code might not expect
it.

View File

@ -0,0 +1,20 @@
title: _gid
---
summary: A globally unique ID of the page.
---
type: sysfield
---
body:
The `_gid` is the MD5 hashed version of the page's [`_path`](../path/). This
is useful in situations where a stable ID is needed that follows a certain
format. For instance it can come in useful when a ID is needed for a DOM
element.
## Example
```html+jinja
<body class="page-{{ this._gid }}">
...
</body>
```

View File

@ -0,0 +1,20 @@
title: _hidden
---
summary: Controls if the page should be built or not.
---
type: sysfield
---
body:
This field controls if Lektor should process the page into a build artifact.
By default each page is built into a build artifact (HTML page) and each
attachment is processed. This can be prevented by setting `_hidden` to `yes`.
This also automatically applies to all children of a page unless they
forcefully override this setting.
This is useful for more advanced setups like [Single Page Applications
:ref](../../../../guides/single-page/).
Hidden pages are automatically also removed from the `.children` property
of records but stay available for querying via the pad.

View File

@ -0,0 +1,32 @@
title: _id
---
summary: The local identifier of a record.
---
type: sysfield
---
body:
Each record has an `_id`. This ID is basically a form of the filename.
Depending on if you are looking at an attachment or a page the rules are
slightly different.
For pages the ID is the name of the folder. So if you have a page called
`docs/overview/contents.lr` then `_id` is `overview`. If you have however
an attachment named `docs/overview/screenshot.jpg` the `_id` will be the
filename of the attachment: `screenshot.jpg`.
Note that IDs are not globally unique! There is also the `_path` which is
the entire path if the record.
The `_id` is automatically set and cannot be overridden.
## Example
```html+jinja
<ul class="nav">
{% for item in site.query('/projects') %}
<li{% if item._id == this._id %} class="active"{%
endif %}>{{ item.name }}</li>
{% endfor %}
</ul>
```

View File

@ -0,0 +1,23 @@
title: _model
---
summary: The model the record uses for its fields.
---
type: sysfield
---
body:
This field selects the model that should be used for non-system fields. In
many situations the model is picked automatically but for equally many
situations it needs to be selected manually.
This field is most useful for filtering when operating on mixed collections.
## Example
```html+jinja
<ul class="projects">
{% for child in this.children.filter(F._model == 'project') %}
<li>{{ child.name }}
{% endfor %}
</ul>
```

View File

@ -0,0 +1,22 @@
title: _path
---
summary: The full path of the record.
---
type: sysfield
---
body:
The `_path` is the more complete version of the [`_id`](../id/). It contains
the entire path of records that are the parents of a record. So if you have a
record named `docs/api/db/contents.lr` the `_id` would be `db` but the `_path`
would be `docs/api/db`.
The path can be used to uniquely identify a page but for that purpose the
[`_gid`](../gid/) can also be used which is a hashed hexadecimal version of
the page.
## Example
```html+jinja
<!-- generated from {{ this._path }} -->
```

View File

@ -0,0 +1,13 @@
title: _slug
---
summary: The URL slug of the record.
---
type: sysfield
---
body:
This field defines the URL slug of the record. If not set it defaults to
either the `_id` or an expansion of what the parent defines for all children.
For more information about this refer to [URLs and Slugs
:ref](../../../../content/urls/).

View File

@ -0,0 +1,20 @@
title: _source_alt
---
summary: The alt from the source of the record.
---
type: sysfield
---
body:
This field points to the true source [Alternative
:ref](../../../../content/alts/) of the page. This primarily exists internally
to support the builder. In particular the difference to the `_alt` field is
that this one will indicate if an alt falls back to a different alternative.
At present pages can only fall back to the `_primary` alternative which will
be reflected by this field.
## Example
```html+jinja
<!-- generated from language {{ this._source_alt }} -->
```

View File

@ -0,0 +1,13 @@
title: _template
---
signature:
---
summary: Selects the template for the page.
---
type: sysfield
---
body:
This field sets the template that Lektor uses for rendering. It defaults to
model name + `.html`. If the `_model` is `page` the name of the template
will be `page.html`. In some situations it makes sense to override this.

View File

@ -0,0 +1,26 @@
title: add_publisher
---
type: method
---
signature: scheme, publisher
---
summary: Registers a publisher class with the environment.
---
body:
This method can be used to register a new publisher for a given URL scheme
with Lektor. This allows plugins to provide custom deployment methods. For
more information on implementing these see [Publisher :ref](../../publisher/).
## Example
```python
from lektor.publisher import Publisher
class MyPublisher(Publisher):
pass
env.add_publisher('my', MyPublisher)
```
---
version_added: 2.0

View File

@ -0,0 +1,23 @@
title: Publisher
---
module: lektor.publisher
---
summary: The interface for extending the deployment process
---
type: class
---
body:
This class can be subclassed to implement custom deployment methods.
Internally these are called “publishers” and to register them with the
environment the [add_publisher :ref](../environment/add-publisher/) method can
be used.
Publishers have one method called [publish :ref](publish/) which is used to
trigger the actual deployment process. It also has a reference back to the
environment it belongs to as well as the output path of the build process.
For a minimal example of a publisher refer to the documentation of the
[publish :ref](publish/) method.
---
version_added: 2.0

View File

@ -0,0 +1,12 @@
title: env
---
summary: Reference to the creating environment
---
type: property
---
version_added: 2.0
---
body:
As each publisher is bound to an [Environment :ref](../../environment/) that
created it. This is useful to discover related information.

View File

@ -0,0 +1,31 @@
title: fail
---
summary: Notifies a failure during publishing
---
signature: message
---
type: method
---
version_added: 2.0
---
body:
This method takes a message and raises an appropriate failure that aborts
the publishing process. This is invoked from within the [publish
:ref](../publish/) method to indicate a failure:
## Example
```python
from lektor.publisher import Publisher
class MyPublisher(Publisher):
def publish(self, target_url, credentials=None, **extra):
self.fail('This publisher cannot publish :(')
class MyPlugin(Plugin):
def on_setup_env(self, **extra):
self.env.add_publisher('my', MyPublisher)
```

View File

@ -0,0 +1,15 @@
title: output_path
---
type: property
---
summary: The path to the folder with the build artifacts
---
version_added: 2.0
---
body:
This attribute holds the path to the folder where the build process put the
final artifacts. Usually a publisher walks that folder and does something
with all contents of it. The publishers however are heavily encourated to
ignore the special `.lektor` folder which contains lektor specific information
that should not end up on the resulting server.

View File

@ -0,0 +1,82 @@
title: publish
---
signature: target_url, credentials=None, **extra
---
summary: The method that triggers the deployment
---
type: method
---
version_added: 2.0
---
body:
This method implements the actual publishing process. It's supposed to
implement a generator that reports the progress of the publishing. If at any
point something happens that would cause an error for the deployment this can
be signalled with the [fail :ref](../fail/) method which aborts the execution
and reports an error.
The parameters to the function are as follows:
* `target_url`: a URL object with the parsed URL. This object comes from the
Werkzeug library and gives access to the individual parts of a URL by the
exposed attributes ([Read about the URL object :ext](http://werkzeug.pocoo.org/docs/0.11/urls/)).
* `credentials`: an optional dictionary with command line supplied credentials.
Note that these credentials might be completely absent and the keys which are
provided might change with future versions of Lektor.
* `**extra`: for forwards compatibility publishers are required to ignore extra
keyword arguments.
Each line in the generator must be a string which is then either logged to
the output in the console or in the deploy/publish window in the admin UI.
## Example
This example implements a simple publisher that just copies all built files
into a new location.
```python
import os
import shutil
from lektor.publisher import Publisher
class CopyPublisher(Publisher):
def publish(self, target_url, credentials=None, **extra):
src_path = self.output_path
dst_path = target_url.path
strip = len(src_path) + 1
for path, folders, filenames in os.walk(src_path):
# Ignore the .lektor folder.
folders[:] = [x for x in folders if x != '.lektor']
# Copy all files over
for filename in filenames:
full_path = os.path.join(src_path, path, filename)
dst = os.path.join(path, full_path[strip:])
# Make sure the destination folder exists.
try:
os.makedirs(os.path.dirname(dst))
except (OSError, IOError):
pass
# Copy the file
yield 'Copy %s' % filename
shutil.copy(full_path, dst)
yield 'Done'
class MyPlugin(Plugin):
def on_setup_env(self, **extra):
self.env.add_publisher('copy', CopyPublisher)
```
This publisher registers with the `copy` scheme and could be used like this:
```ini
target_url = copy:///path/to/destination/folder
```

View File

@ -0,0 +1,22 @@
title: markdown
---
signature: source
---
summary: Converts markdown to HTML
---
type: filter
---
version_added: 2.0
---
body:
This filter converts a markdown string into HTML. This behaves the same as
the [Markdown Type :ref](../../../db/types/markdown/).
## Example
```html+jinja
<div class="example">
{{ "Hello **World**"|markdown }}
</div>
```

View File

@ -49,7 +49,7 @@ Each page is associated with a model and a template. Each page needs to have
a model that defines which fields exist. The template by default matches the a model that defines which fields exist. The template by default matches the
model name but it can be overridden on a per-page basis. model name but it can be overridden on a per-page basis.
So how is the model selected? Either expicitly in the `contents.lr` file So how is the model selected? Either explicitly in the `contents.lr` file
with the `_model` key or by configuration and convention. Lektor will with the `_model` key or by configuration and convention. Lektor will
select the default model based on trying things in this order: select the default model based on trying things in this order:
@ -80,11 +80,15 @@ The page body goes here
Fields are separated by three dashes `---` and follow the format `key: value`. Fields are separated by three dashes `---` and follow the format `key: value`.
For values with multiple lines it's recommended to insert two newlines after For values with multiple lines it's recommended to insert two newlines after
the key. To format of each field is specific to how the model is configured. the key. The format of each field is specific to how the model is configured.
Some fields are plain text, others can be markdown syntax and more. These Some fields are plain text, others can be markdown syntax and more. These
fields become available for rendering in the template automatically. fields become available for rendering in the template automatically.
**Tip:** If you want to use `---` itself in the document text, just add another !!! If you want to use `---` itself in the document text, just add another
dash. This means `----` will render as `---` and `-----` will render as dash. This means `----` will render as `---` and `-----` will render as
`----` etc. `----` etc.
Fields prefixed with an underscore are so-called system fields. They are
provided by Lektor and customize behavior within Lektor. For a list of
available fields see [System Fields :ref](../api/db/system-fields/).

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -101,6 +101,10 @@ The following targets are supported for the `target` folder:
* [FTP](ftp/) * [FTP](ftp/)
* [GitHub Pages](ghpages/) * [GitHub Pages](ghpages/)
In addition, third-party plugins are available for these targets:
* [S3 :ext](https://github.com/spenczar/lektor-s3)
## Manual Deployments ## Manual Deployments
If you want to manually deploy something through the favorite tool of yours If you want to manually deploy something through the favorite tool of yours

View File

@ -8,7 +8,7 @@ body:
* `ghpages+https://username/repository` * `ghpages+https://username/repository`
A popular way to host websites for Open Source projects is the GitHub pages. A popular way to host websites for Open Source projects is the GitHub pages.
It's a free services provided by [GitHub :ext](http://github.com/) which allows It's a free service provided by [GitHub :ext](http://github.com/) which allows
to host completely static websites through GitHub. to host completely static websites through GitHub.
The way this is implemented in Lektor currently is that Lektor will force-push The way this is implemented in Lektor currently is that Lektor will force-push

View File

@ -123,7 +123,7 @@ For the detail page we show all information we know about:
{% block title %}{{ this.name }} ({{ this.date.year }}){% endblock %} {% block title %}{{ this.name }} ({{ this.date.year }}){% endblock %}
{% block body %} {% block body %}
<h1>{{ this.name }}</h1> <h1>{{ this.name }}</h1>
<dt> <dl>
<dt>Date <dt>Date
<dd>{{ this.date|dateformat }} <dd>{{ this.date|dateformat }}
{% if this.website %} {% if this.website %}

View File

@ -23,6 +23,10 @@ _model: none
This instructs Lektor to use the template `sitemap.xml` for this page. We This instructs Lektor to use the template `sitemap.xml` for this page. We
also give it the empty `none` model for good measure. also give it the empty `none` model for good measure.
!!! Starting with Lektor 2.0 you can also add `_discoverable: no` as field
into the file to hide it from `.children`. This is useful for such special
pages which should be excluded from navigation or automatic link generation.
## Template File ## Template File
The template loaded will be `templates/sitemap.xml`. In this file we just The template loaded will be `templates/sitemap.xml`. In this file we just

View File

@ -6,10 +6,10 @@ sort_key: 50
--- ---
body: body:
Lektor comes in two flavors: the command line executable as well as as a Lektor comes in two flavors: as a command line executable and as a
desktop application. The desktop version also contains the command line desktop application. The desktop version also contains the command
executable however it bundles together all dependencies of Lektor in an line executable, but it also bundles together all dependencies of Lektor
easy to use package which heavily simplifies installation. in an easy to use package which heavily simplifies installation.
## Desktop Application ## Desktop Application
@ -20,23 +20,23 @@ disk image that you can mount which contains one application by the name of
go. go.
If you also want access to the command line tools just launch `Lektor.app` If you also want access to the command line tools just launch `Lektor.app`
and then click on *Lektor ➤ Install Shell Command*. and then click in the menu bar on *Lektor ➤ Install Shell Command*.
## Command Line Application ## Command Line Application
If you do not want to install the desktop app you can just install the command If you do not want to install the desktop app then you can just install the command
line executable. This one runs on more operating systems (OSX, Linux and line executable. This runs on more operating systems (OSX, Linux and Windows) but
Windows) but the installation is a bit more involved. the installation is a bit more involved.
You need to make sure you have the following software installed on your computer: You need to make sure you have the following software installed on your computer:
* Python 2.7 (**not** Python 3.x) * Python 2.7 (**not** Python 3.x, also `python-dev` is required on Ubuntu)
* ImageMagick (`brew install imagemagick` or `apt-get install imagemagick` * ImageMagick (`brew install imagemagick` or `apt-get install imagemagick`
can get you this on OS X and Ubuntu respectively, on Windows do `choco can get you this on OS X and Ubuntu respectively, on Windows do `choco
install imagemagick`, which requires [chocolatey :ext](https://chocolatey.org/), install imagemagick`, which requires [chocolatey :ext](https://chocolatey.org/),
or [download from here :ext](http://www.imagemagick.org)). or [download from here :ext](http://www.imagemagick.org)).
Once you have that installed and made sure that they are on your `PATH` you can Once you have those installed and have made sure that they are on your `PATH`, you can
get Lektor installed with our installation script: get Lektor installed with our installation script:
``` ```
@ -53,8 +53,11 @@ but you can also do it directly in `Powershell`:
PS C:\> iex ((new-object net.webclient).DownloadString('https://getlektor.com/install.ps1')) PS C:\> iex ((new-object net.webclient).DownloadString('https://getlektor.com/install.ps1'))
``` ```
Alternatively you can manually install it with `virtualenv` if you know ## pip
how that works:
Alternatively you can manually install the command line version with
`virtualenv` if you know how that works. Note that this method is *heavily
discouraged* for anything other than advanced use cases such as build servers.
``` ```
$ virtualenv venv $ virtualenv venv
@ -62,6 +65,12 @@ $ . venv/bin/activate
$ pip install Lektor $ pip install Lektor
``` ```
!!!! When we say this installation type is discouraged we mean it. The reason
is that it encourages uses of Lektor which are entirely unsupported by us.
Lektor actively manages virtualenvs for plugin installations in very specific
ways and this might or might not work in your setup. We support pip
installations for deployment environments and local development only.
## Development Version ## Development Version
If you want to install the development version of Lektor you can do so. It's If you want to install the development version of Lektor you can do so. It's

View File

@ -108,10 +108,10 @@ class HelloWorldPlugin(Plugin):
If you now start your lektor server with `lektor server` you should If you now start your lektor server with `lektor server` you should
see some output that indicates that the plugin was loaded. You can also see some output that indicates that the plugin was loaded. You can also
get a list with `lektor plugins`: get a list with `lektor plugins list`:
``` ```
$ lektor plugins $ lektor plugins list
hello-world: Hello World hello-world: Hello World
This is a demo plugin for testing purposes. This is a demo plugin for testing purposes.
path: /Users/john/demo/packages/hello-world path: /Users/john/demo/packages/hello-world

View File

@ -17,10 +17,16 @@ project:
this plugin embeds disqus comments into your website. this plugin embeds disqus comments into your website.
* [webpack-support :ext](https://github.com/lektor/lektor-webpack-support): * [webpack-support :ext](https://github.com/lektor/lektor-webpack-support):
adds support for building websites with webpack. adds support for building websites with webpack.
* [markdown-highlighter :ext](https://github.com/lektor/lektor-markdown-highlighter):
adds support for syntax highlighting to markdown code snippets.
* [markdown-header-anchors :ext](https://github.com/lektor/lektor-markdown-header-anchors):
adds support for header anchors and table of contents to markdown.
## Inofficial ## Unofficial
There are currently no inofficial plugins listed here, but if you have some These are unofficial plugins. This list is moderated and updated
you can [edit this page on github regularly, but they still aren't developed by the authors of Lektor,
:ext](https://github.com/lektor/lektor-website/edit/master/content/docs/plugins/list/contents.lr) so they might not keep pace with development on Lektor.
and send a pull request.
* [s3 :ext](https://github.com/spenczar/lektor-s3):
allows deployment of websites to S3 buckets

View File

@ -87,7 +87,7 @@ but are contained within a field of a model.
### `packages/` ### `packages/`
For local plugin development the `packages/` folder can be used. Any plugin For local plugin development the `packages/` folder can be used. Any plugin
stored in there is automatically actviated in the system. stored in there is automatically activated in the system.
### `configs/` ### `configs/`

Binary file not shown.

Before

Width:  |  Height:  |  Size: 209 KiB

After

Width:  |  Height:  |  Size: 118 KiB

View File

@ -50,7 +50,7 @@ $ lektor server
``` ```
This will automatically start the server and you can navigate to This will automatically start the server and you can navigate to
[localhost:5000](http://localhost:5000/) go open the project. [localhost:5000](http://localhost:5000/) open the project.
You can keep the server running, it will automatically rebuild your files as You can keep the server running, it will automatically rebuild your files as
they change. they change.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 241 KiB

After

Width:  |  Height:  |  Size: 157 KiB

View File

@ -6,8 +6,8 @@ sort_key: 20
--- ---
body: body:
When it comes to creating websites, there is a ludicrous amount of tools available. When it comes to creating websites, there is a ludicrous number of tools available.
They range from full blown content management solutions like Drupal over They range from full-blown content management solutions like Drupal to
desktop solutions like Google Web Designer to Cloud Hosted Website solutions desktop solutions like Google Web Designer to Cloud Hosted Website solutions
like WIX to more programmer focused approaches like Jekyll which generate like WIX to more programmer focused approaches like Jekyll which generate
websites out of templates and markdown files. websites out of templates and markdown files.
@ -17,31 +17,31 @@ websites out of templates and markdown files.
## Lektor is Static ## Lektor is Static
Lektor learned from the huge range of static file generators like Jekyll, Lektor learned from the huge range of static file generators like Jekyll,
Pelican, Hugo, Middleman and many more about the values of generating a Pelican, Hugo, Middleman and many more about the value of generating a
completely static website. This means that unlike WordPress or similar completely static website. This means that unlike WordPress or similar
solutions it does not run on a server, but your local computer (or a build solutions it does not run on a server, but your local computer (or a build
server) and generates out static HTML that can be uploaded to any web server server), and generates static HTML that can be uploaded to any web server or
or content distribution platform like S3 with CloudFront. content distribution platform like S3 with CloudFront.
Why go static? Because the vast, vast majority of websites will be read many Why go static? Because the vast, vast majority of websites will be read many
more times than they will update. This is crucial because dynamic does not more times than they will be updated. This is crucial because dynamic content
come for free. It needs server resources and because program code is running does not come for free. It needs server resources and because program code is
there it needs to be kept up to date for to ensure there are no security running there it needs to be kept up to date for to ensure there are no security
problems that are left unpatched. Also when a website gets a sudden spike problems that are left unpatched. Also when a website gets a sudden spike of
of traffic a static website will stay up for longer on the same server than traffic a static website will stay up for longer on the same server than a
a dynamic one that needs to execute code. dynamic one that needs to execute code.
Sure, there are some things you cannot do on a static website, but those Sure, there are some things you cannot do on a static website, but those are not
things you would not use Lektor for. For small dynamic sections, JavaScript things you would not use Lektor for. For small dynamic sections, JavaScript
and pairing up with other services is a good solution. paired up with other services is a good solution.
<img src="static.png" alt="" class="screenshot"> <img src="static.png" alt="" class="screenshot">
## Lektor is a CMS ## Lektor is a CMS
However Lektor also takes from content management systems like WordPress However, Lektor also takes from content management systems like WordPress
and provides a flexible browser based admin interface from which you can and provides a flexible browser-based admin interface from which you can
edit your website's contents. Unlike traditional CMS solutions however it edit your website's contents. Unlike traditional CMS solutions, however, it
runs entirely on your own computer. runs entirely on your own computer.
This means you can give a Lektor website to people that have no understanding This means you can give a Lektor website to people that have no understanding
@ -51,7 +51,7 @@ of programming and they can still modify the content and update the website.
## Lektor is a Framework ## Lektor is a Framework
Lastly however Lektor learns from experience in writing web frameworks. Lektor Lastly, Lektor learns from experience in writing web frameworks. Lektor
is much more than a website generator because it is based on a very flexible is much more than a website generator because it is based on a very flexible
internal flat file database which can be used to model any website content. internal flat file database which can be used to model any website content.
Unlike static blog generators which are based on some markdown content and Unlike static blog generators which are based on some markdown content and

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 KiB

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 200 KiB

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 237 KiB

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 460 KiB

After

Width:  |  Height:  |  Size: 433 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 237 KiB

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 331 KiB

After

Width:  |  Height:  |  Size: 219 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 299 KiB

After

Width:  |  Height:  |  Size: 261 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 262 KiB

After

Width:  |  Height:  |  Size: 240 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 294 KiB

After

Width:  |  Height:  |  Size: 175 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 306 KiB

After

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 294 KiB

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 270 KiB

After

Width:  |  Height:  |  Size: 152 KiB

View File

@ -6,23 +6,16 @@ button_label = [[flag]]
label = Image label = Image
type = select type = select
source = record.attachments.images source = record.attachments.images
width = 2/4 width = 3/4
[fields.height] [fields.height]
label = Height label = Height
type = select type = select
choices = half, full, 500, 300 choices = 500, 300
choice_labels = Half, Full, 500px, 300px choice_labels = 500px, 300px
default = 300 default = 300
width = 1/4 width = 1/4
[fields.class]
label = Class
type = select
choices = dark
choice_labels = Dark
width = 1/4
[fields.contents] [fields.contents]
label = Contents label = Contents
type = html type = html

View File

@ -28,16 +28,12 @@ default = yes
checkbox_label = Show comment box checkbox_label = Show comment box
width = 1/4 width = 1/4
[fields.body]
label = Body
type = markdown
[fields.type] [fields.type]
label = Technical Type label = Technical Type
type = select type = select
description = Of what general type this doc page is. If not set, it's a normal doc page. description = Of what general type this doc page is. If not set, it's a normal doc page.
choices = class, function, method, property, operator, filter, cmdlet, event, type choices = class, function, method, property, operator, filter, cmdlet, event, type, sysfield
choice_labels = Class, Function, Method, Property, Operator, Filter, Commandlet, Event, Field Type choice_labels = Class, Function, Method, Property, Operator, Filter, Commandlet, Event, Field Type, System Field
width = 1/2 width = 1/2
[fields.module] [fields.module]
@ -57,3 +53,11 @@ description = An optional signature for a type.
label = Template Variable label = Template Variable
type = string type = string
description = An optional template variable if it exists there as such. description = An optional template variable if it exists there as such.
[fields.version_added]
label = Added in version
type = string
[fields.body]
label = Body
type = markdown

View File

@ -0,0 +1,5 @@
dist
build
*.pyc
*.pyo
*.egg-info

View File

@ -0,0 +1,34 @@
# -*- coding: utf-8 -*-
import re
from lektor.pluginsystem import Plugin
_prefix_re = re.compile(r'^\s*(!{1,4})\s+')
CLASSES = {
1: 'note',
2: 'info',
3: 'tip',
4: 'warning',
}
class AdmonitionMixin(object):
def paragraph(self, text):
match = _prefix_re.match(text)
if match is None:
return super(AdmonitionMixin, self).paragraph(text)
level = len(match.group(1))
return '<div class="admonition admonition-%s"><p>%s</p></div>' % (
CLASSES[level],
text[match.end():]
)
class MarkdownAdmonitionPlugin(Plugin):
name = u'Markdown Admonition'
description = u'Adds admonitions to markdown.'
def on_markdown_config(self, config, **extra):
config.renderer_mixins.append(AdmonitionMixin)

View File

@ -0,0 +1,15 @@
from setuptools import setup
setup(
name='lektor-markdown-admonition',
version='0.1',
author=u'Armin Ronacher',
author_email='armin.ronacher@active-4.com',
license='MIT',
py_modules=['lektor_markdown_admonition'],
entry_points={
'lektor.plugins': [
'markdown-admonition = lektor_markdown_admonition:MarkdownAdmonitionPlugin',
]
}
)

View File

@ -1,42 +0,0 @@
from lektor.pluginsystem import Plugin
from lektor.utils import slugify
from markupsafe import Markup
from collections import namedtuple
TocEntry = namedtuple('TocEntry', ['anchor', 'title', 'children'])
class MarkdownHeaderAnchorsPlugin(Plugin):
name = 'Markdown Header Anchors'
description = 'Adds anchors to markdown headers.'
def on_markdown_config(self, config, **extra):
class HeaderAnchorMixin(object):
def header(renderer, text, level, raw):
anchor = slugify(raw)
renderer.meta['toc'].append((level, anchor, Markup(text)))
return '<h%d id="%s">%s</h%d>' % (level, anchor, text, level)
config.renderer_mixins.append(HeaderAnchorMixin)
def on_markdown_meta_init(self, meta, **extra):
meta['toc'] = []
def on_markdown_meta_postprocess(self, meta, **extra):
prev_level = None
toc = []
stack = [toc]
for level, anchor, title in meta['toc']:
if prev_level is None:
prev_level = level
elif prev_level == level - 1:
stack.append(stack[-1][-1][2])
prev_level = level
elif prev_level > level:
while prev_level > level:
stack.pop()
prev_level -= 1
stack[-1].append(TocEntry(anchor, title, []))
meta['toc'] = toc

View File

@ -1,12 +0,0 @@
from setuptools import setup
setup(
name='lektor-markdown-header-anchors',
version='0.1',
py_modules=['lektor_markdown_header-anchors'],
entry_points={
'lektor.plugins': [
'markdown-header-anchors = lektor_markdown_header_anchors:MarkdownHeaderAnchorsPlugin',
]
}
)

View File

@ -1,49 +0,0 @@
from lektor.pluginsystem import Plugin
from lektor.context import get_ctx
from pygments import highlight
from pygments.formatters import HtmlFormatter
from pygments.lexers import get_lexer_by_name
from markupsafe import Markup
class MarkdownHighlighterPlugin(Plugin):
name = 'Markdown Highlighter'
description = 'Adds syntax highlighting for markdown blocks.'
def get_formatter(self):
return HtmlFormatter(style=self.get_style())
def get_style(self):
return self.get_config().get('pygments.style', 'default')
def highlight_code(self, text, lang):
get_ctx().record_dependency(self.config_filename)
lexer = get_lexer_by_name(lang)
return highlight(text, lexer, self.get_formatter())
def on_markdown_config(self, config, **extra):
class HighlightMixin(object):
def block_code(ren, text, lang):
if not lang:
return super(HighlightMixin, ren).block_code(text, lang)
return self.highlight_code(text, lang)
config.renderer_mixins.append(HighlightMixin)
def on_setup_env(self, **extra):
def get_pygments_stylesheet(artifact_name='/static/pygments.css'):
ctx = get_ctx()
@ctx.sub_artifact(artifact_name=artifact_name, sources=[
self.config_filename])
def build_stylesheet(artifact):
with artifact.open('w') as f:
f.write(self.get_formatter().get_style_defs())
return artifact_name
def pygmentize(text, lang):
return Markup(self.highlight_code(text, lang))
self.env.jinja_env.globals['get_pygments_stylesheet'] = \
get_pygments_stylesheet
self.env.jinja_env.filters['pygmentize'] = pygmentize

View File

@ -1,15 +0,0 @@
from setuptools import setup
setup(
name='lektor-markdown-highlighter',
version='0.1',
py_modules=['lektor_markdown_highlighter'],
entry_points={
'lektor.plugins': [
'markdown-highlighter = lektor_markdown_highlighter:MarkdownHighlighterPlugin',
]
},
install_requires=[
'Pygments',
]
)

View File

@ -1,8 +1,5 @@
{% set image = record.attachments.get(this.image) %} {% set image = record.attachments.get(this.image) %}
<div class="banner{% if this.class %} banner-{{ this.class }}{% endif %}" style="background-image: url({{ image|url <div class="banner banner-{{ this.height }}" style="background-image: url({{ image|url
}}); height: {{ { }})">{% if this.contents %}
'full': image.height,
'half': image.height / 2,
}.get(this.height, this.height) }}px">{% if this.contents %}
{{ this.contents }} {{ this.contents }}
{% endif %}</div> {% endif %}</div>

View File

@ -2,7 +2,7 @@
<div class="slideshow-wrapper"> <div class="slideshow-wrapper">
<div class="slideshow"> <div class="slideshow">
<div class="slideshow-inner"> <div class="slideshow-inner">
<div class="carousel slide" data-ride="carousel" id="{{ carousel_id }}"> <div class="carousel slide" data-ride="carousel" data-interval="8500" id="{{ carousel_id }}">
{# {#
<ol class="carousel-indicators"> <ol class="carousel-indicators">
{% for slide in this.slides.blocks %} {% for slide in this.slides.blocks %}

View File

@ -33,21 +33,35 @@
<div class="col-sm-9 doc-styling"> <div class="col-sm-9 doc-styling">
{{ get_doc_header(this) }} {{ get_doc_header(this) }}
<ul class=page-meta>
{% if this.type == 'method' %} {% if this.type == 'method' %}
<p class="type-info">Method of {{ get_doc_link(this.parent) }} <li>Method of {{ get_doc_link(this.parent) }}
{% elif this.type == 'property' %} {% elif this.type == 'property' %}
<p class="type-info">Property of {{ get_doc_link(this.parent) }} <li>Property of {{ get_doc_link(this.parent) }}
{% elif this.type == 'operator' %} {% elif this.type == 'operator' %}
<p class="type-info">Operator of {{ get_doc_link(this.parent) }} <li>Operator of {{ get_doc_link(this.parent) }}
{% endif %} {% endif %}
{% if this.template_var %} {% if this.template_var %}
<p class="type-info">Template variable: <a href="{{ ( <li>Template variable: <a href="{{ (
'/docs/api/templates/globals/' ~ this.template_var|lower ~ '/')|url '/docs/api/templates/globals/' ~ this.template_var|lower ~ '/')|url
}}"><code>{{ this.template_var }}</code></a> }}"><code>{{ this.template_var }}</code></a>
{% endif %} {% endif %}
{% if this.version_added %}
<li>New in Lektor Version <em>{{ this.version_added }}</em>
{% endif %}
</ul>
{{ this.body }} {{ this.body }}
{% if this.version_history %}
<div class="version-info version-info-collapsed">
<h2>Version Info</h2>
<div class="contents">
{{ this.version_history }}
</div>
</div>
{% endif %}
{% if this.children %} {% if this.children %}
<div class="child-pages"> <div class="child-pages">
{% for cols in this.children|batch(2) %} {% for cols in this.children|batch(2) %}

View File

@ -56,6 +56,8 @@
><i class="fa fa-bug"></i></a> ><i class="fa fa-bug"></i></a>
<a href="https://twitter.com/getlektor" title="Find Lektor on Twitter" <a href="https://twitter.com/getlektor" title="Find Lektor on Twitter"
><i class="fa fa-twitter"></i></a> ><i class="fa fa-twitter"></i></a>
<a href="https://gitter.im/lektor/lektor" title="Chat on Gitter"
><i class="fa fa-comment"></i></a>
{%- if this.path %} {%- if this.path %}
<a href="https://github.com/lektor/lektor-website/tree/master/content{{ this.path <a href="https://github.com/lektor/lektor-website/tree/master/content{{ this.path
}}/contents.lr" title="View source for this page"><i class="fa fa-code"></i></a> }}/contents.lr" title="View source for this page"><i class="fa fa-code"></i></a>

View File

@ -11,7 +11,7 @@
<i class="glyphicon glyphicon-console"></i> <i class="glyphicon glyphicon-console"></i>
{%- elif page.type == 'event' -%} {%- elif page.type == 'event' -%}
<i class="glyphicon glyphicon-flash"></i> <i class="glyphicon glyphicon-flash"></i>
{%- elif page.type == 'type' -%} {%- elif page.type == 'type' or page.type == 'sysfield' -%}
<i class="glyphicon glyphicon-pencil"></i> <i class="glyphicon glyphicon-pencil"></i>
{%- else -%} {%- else -%}
<i class="glyphicon glyphicon-list-alt"></i> <i class="glyphicon glyphicon-list-alt"></i>

View File

@ -15,6 +15,29 @@ function selectText(text) {
} }
} }
function initBadges() {
let badges = $('.badges li').hide();
if (badges.length <= 0) {
return;
}
let nextBadge = 0;
function fadeInNext() {
let el = badges[nextBadge++];
if (!el) {
return;
}
window.setTimeout(fadeInNext, 200);
$(el).fadeIn();
}
window.setTimeout(function() {
fadeInNext();
}, 1000);
}
function initDownloadButton() { function initDownloadButton() {
let buttons = $('.download-btn'); let buttons = $('.download-btn');
if (buttons.length <= 0) { if (buttons.length <= 0) {
@ -143,6 +166,7 @@ function hideThingsForWindows() {
} }
$(function() { $(function() {
initBadges();
initDownloadButton(); initDownloadButton();
initInstallRow(); initInstallRow();
initGoogleSearch(); initGoogleSearch();

View File

@ -103,7 +103,7 @@ div.slideshow {
height: auto; height: auto;
overflow: auto; overflow: auto;
background: lighten($gray, 55) url(../images/dark-curls.png); background: lighten($gray, 55) url(../images/dark-curls.png);
box-shadow: inset 0 0 10px darken($lektor-header-bg, 5); box-shadow: inset 0 0 10px fade-out(darken($lektor-header-bg, 5), 0.8);
color: white; color: white;
div.slideshow-inner { div.slideshow-inner {
@ -259,14 +259,24 @@ div.banner {
margin: 15px 0; margin: 15px 0;
background-size: cover; background-size: cover;
background-position: center center; background-position: center center;
background-color: $lektor-header-bg;
&:first-child { &:first-child {
margin-top: 0; margin-top: 0;
box-shadow: 0 4px 10px fade-out($gray, 0.8);
} }
&.banner-dark { &.banner-500 {
background-color: $lektor-header-bg; height: 500px;
@media (max-width: $screen-md-max) { height: 300px; }
@media (max-width: $screen-sm-max) { height: 200px; }
}
&.banner-300 {
height: 300px;
@media (max-width: $screen-md-max) { height: 200px; }
@media (max-width: $screen-sm-max) { height: 120px; }
} }
} }
@ -291,11 +301,24 @@ div.doc-styling {
} }
} }
p.type-info { ul.page-meta {
list-style: none;
font-style: italic; font-style: italic;
margin: 0;
padding: 0 0 0 30px;
line-height: 1.4;
> li {
margin: 0;
padding: 0;
&:last-child {
margin-bottom: 10px;
}
em {
background: #eee;
}
} }
p.type-info + p.type-info {
margin-top: 0;
} }
table { table {
@ -314,6 +337,10 @@ div.doc-styling {
padding: 5px 10px; padding: 5px 10px;
} }
tr {
background: white;
}
tr:nth-child(odd) { tr:nth-child(odd) {
background: #f8f8f8; background: #f8f8f8;
} }
@ -600,6 +627,56 @@ div.sourceviewer {
} }
} }
div.admonition {
margin: 15px 0;
background: white;
padding: 10px 15px;
padding-bottom: 0;
&:before {
margin: -10px -15px 10px -15px;
padding: 10px 15px;
line-height: 1;
background: #ccc;
display: block;
content: "";
font-weight: bold;
font-size: 13px;
}
&.admonition-note {
&:before {
content: "Note";
background: #8FC4E0;
}
border: 1px solid #8FC4E0;
}
&.admonition-info {
&:before {
content: "Info";
background: #E0C18F;
}
border: 1px solid #E0C18F;
}
&.admonition-tip {
&:before {
content: "Tip";
background: #9EB675;
}
border: 1px solid #9EB675;
}
&.admonition-warning {
&:before {
content: "Warning";
background: #E0AA8F;
}
border: 1px solid #E0AA8F;
}
}
/* search */ /* search */
div.doc-styling div.gsc-control-cse { div.doc-styling div.gsc-control-cse {
font-family: $font-family-base!important; font-family: $font-family-base!important;