Merge remote-tracking branch 'refs/remotes/origin/master' into feature/documentation
|
@ -3,10 +3,17 @@ python: 2.7
|
|||
install:
|
||||
- "pip install -U pip"
|
||||
- "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:
|
||||
directories:
|
||||
- $HOME/.cache/pip
|
||||
- $HOME/.cache/lektor/builds
|
||||
addons:
|
||||
ssh_known_hosts: flow.srv.pocoo.org
|
||||
|
||||
notifications:
|
||||
webhooks:
|
||||
urls:
|
||||
- https://webhooks.gitter.im/e/f0c538cdfc9883f81e34
|
||||
|
|
|
@ -12,3 +12,5 @@ default = yes
|
|||
[packages]
|
||||
lektor-webpack-support = 0.1
|
||||
lektor-disqus-comments = 0.1
|
||||
lektor-markdown-header-anchors = 0.1
|
||||
lektor-markdown-highlighter = 0.1
|
||||
|
|
|
@ -24,6 +24,7 @@ if 1:
|
|||
import json
|
||||
import urllib
|
||||
import tempfile
|
||||
import shutil
|
||||
from subprocess import Popen
|
||||
|
||||
sys.stdin = open('/dev/tty', 'r')
|
||||
|
@ -59,6 +60,32 @@ if 1:
|
|||
os.path.dirname(path), 'lib', 'lektor')
|
||||
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):
|
||||
print 'Error: %s' % message
|
||||
sys.exit(1)
|
||||
|
@ -67,17 +94,19 @@ if 1:
|
|||
t = tempfile.mkdtemp()
|
||||
Popen('curl -sf "%s" | tar -xzf - --strip-components=1' %
|
||||
virtualenv_url, shell=True, cwd=t).wait()
|
||||
|
||||
try:
|
||||
os.makedirs(lib_dir)
|
||||
except OSError:
|
||||
pass
|
||||
Popen(['./virtualenv.py', lib_dir], cwd=t).wait()
|
||||
Popen([os.path.join(lib_dir, 'bin', 'pip'),
|
||||
'install', '--upgrade', 'Lektor']).wait()
|
||||
'install', '--upgrade', 'Lektor']).wait()
|
||||
os.symlink(os.path.join(lib_dir, 'bin', 'lektor'),
|
||||
os.path.join(bin_dir, 'lektor'))
|
||||
|
||||
def main():
|
||||
print
|
||||
print 'Welcome to Lektor'
|
||||
print
|
||||
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:
|
||||
fail('Could not determine installation location for Lektor.')
|
||||
|
||||
check_installation(lib_dir, bin_dir)
|
||||
|
||||
print 'Installing at:'
|
||||
print ' bin: %s' % bin_dir
|
||||
print ' app: %s' % lib_dir
|
||||
print
|
||||
|
||||
while 1:
|
||||
input = raw_input('Continue? [Yn] ').lower().strip()
|
||||
if input in ('', 'y'):
|
||||
break
|
||||
elif input == 'n':
|
||||
print 'Aborted!'
|
||||
sys.exit()
|
||||
get_confirmation()
|
||||
|
||||
for url in json.load(urllib.urlopen(VENV_URL))['urls']:
|
||||
if url['python_version'] == 'source':
|
||||
|
|
|
@ -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
|
||||
* http://jquery.com/
|
||||
*
|
||||
|
|
|
@ -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":""}
|
Before Width: | Height: | Size: 1.5 MiB After Width: | Height: | Size: 1.4 MiB |
Before Width: | Height: | Size: 226 KiB After Width: | Height: | Size: 211 KiB |
Before Width: | Height: | Size: 279 KiB After Width: | Height: | Size: 171 KiB |
Before Width: | Height: | Size: 415 KiB After Width: | Height: | Size: 368 KiB |
Before Width: | Height: | Size: 241 KiB After Width: | Height: | Size: 158 KiB |
|
@ -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>
|
After Width: | Height: | Size: 272 KiB |
Before Width: | Height: | Size: 337 KiB After Width: | Height: | Size: 314 KiB |
|
@ -9,8 +9,6 @@ image: header.jpg
|
|||
----
|
||||
height: 500
|
||||
----
|
||||
class: dark
|
||||
----
|
||||
contents:
|
||||
|
||||
<div class="container lektor-intro">
|
||||
|
@ -37,6 +35,9 @@ contents:
|
|||
data-count-api="/repos/lektor/lektor#stargazers_count"
|
||||
data-count-aria-label="# stargazers on GitHub"
|
||||
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>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -74,7 +75,7 @@ text:
|
|||
system is written in Python and provides a documented API to extend it and
|
||||
integrate into other apps.
|
||||
* <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
|
||||
#### slideshow ####
|
||||
|
|
|
@ -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 %}
|
||||
```
|
|
@ -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.
|
|
@ -10,8 +10,9 @@ body:
|
|||
|
||||
This controls how the query should behave with regards to hidden records.
|
||||
A query created from the [children :ref](../../record/children/) attribute of
|
||||
a record will not include hidden records by default. The opposite is true
|
||||
for queries created from the [query :ref](../../pad/query/) method of the pad.
|
||||
a record will not include hidden records (or undiscoverable) by default. The
|
||||
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
|
||||
hidden records.
|
||||
|
|
|
@ -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>
|
||||
```
|
|
@ -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']
|
||||
```
|
|
@ -15,17 +15,23 @@ overview page.
|
|||
|
||||
The following attributes exist on the pagination object:
|
||||
|
||||
| Attribute | Description
|
||||
| ----------- | ------------
|
||||
| `current` | The current record
|
||||
| `prev` | The record for the last page (might be `None`)
|
||||
| `next` | The record for the net page (might be `None`)
|
||||
| `total` | The total number of items across all pages
|
||||
| `pages` | The total number of pages
|
||||
| `page` | The number of current page
|
||||
| `has_prev` | `True` if a previous page exists
|
||||
| `has_next` | `True` if a next page exists
|
||||
| `items` | The query that resolves to the children of the current page.
|
||||
| Attribute | Description
|
||||
| ------------ | ------------
|
||||
| `current` | The current record
|
||||
| `prev` | The record for the last page (might be `None`)
|
||||
| `next` | The record for the net page (might be `None`)
|
||||
| `total` | The total number of items across all pages
|
||||
| `pages` | The total number of pages
|
||||
| `page` | The number of current page
|
||||
| `has_prev` | `True` if a previous page exists
|
||||
| `has_next` | `True` if a next page exists
|
||||
| `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
|
||||
|
||||
|
|
|
@ -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.
|
|
@ -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.
|
|
@ -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).
|
|
@ -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.
|
|
@ -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>
|
||||
```
|
|
@ -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.
|
|
@ -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>
|
||||
```
|
|
@ -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>
|
||||
```
|
|
@ -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 }} -->
|
||||
```
|
|
@ -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/).
|
|
@ -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 }} -->
|
||||
```
|
|
@ -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.
|
|
@ -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
|
|
@ -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
|
|
@ -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.
|
|
@ -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)
|
||||
```
|
|
@ -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.
|
|
@ -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
|
||||
```
|
|
@ -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>
|
||||
```
|
|
@ -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
|
||||
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
|
||||
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`.
|
||||
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
|
||||
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
|
||||
`----` 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/).
|
||||
|
|
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 22 KiB |
|
@ -101,6 +101,10 @@ The following targets are supported for the `target` folder:
|
|||
* [FTP](ftp/)
|
||||
* [GitHub Pages](ghpages/)
|
||||
|
||||
In addition, third-party plugins are available for these targets:
|
||||
|
||||
* [S3 :ext](https://github.com/spenczar/lektor-s3)
|
||||
|
||||
## Manual Deployments
|
||||
|
||||
If you want to manually deploy something through the favorite tool of yours
|
||||
|
|
|
@ -8,7 +8,7 @@ body:
|
|||
* `ghpages+https://username/repository`
|
||||
|
||||
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.
|
||||
|
||||
The way this is implemented in Lektor currently is that Lektor will force-push
|
||||
|
|
|
@ -123,7 +123,7 @@ For the detail page we show all information we know about:
|
|||
{% block title %}{{ this.name }} ({{ this.date.year }}){% endblock %}
|
||||
{% block body %}
|
||||
<h1>{{ this.name }}</h1>
|
||||
<dt>
|
||||
<dl>
|
||||
<dt>Date
|
||||
<dd>{{ this.date|dateformat }}
|
||||
{% if this.website %}
|
||||
|
|
|
@ -23,6 +23,10 @@ _model: none
|
|||
This instructs Lektor to use the template `sitemap.xml` for this page. We
|
||||
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
|
||||
|
||||
The template loaded will be `templates/sitemap.xml`. In this file we just
|
||||
|
|
|
@ -6,10 +6,10 @@ sort_key: 50
|
|||
---
|
||||
body:
|
||||
|
||||
Lektor comes in two flavors: the command line executable as well as as a
|
||||
desktop application. The desktop version also contains the command line
|
||||
executable however it bundles together all dependencies of Lektor in an
|
||||
easy to use package which heavily simplifies installation.
|
||||
Lektor comes in two flavors: as a command line executable and as a
|
||||
desktop application. The desktop version also contains the command
|
||||
line executable, but it also bundles together all dependencies of Lektor
|
||||
in an easy to use package which heavily simplifies installation.
|
||||
|
||||
## Desktop Application
|
||||
|
||||
|
@ -20,23 +20,23 @@ disk image that you can mount which contains one application by the name of
|
|||
go.
|
||||
|
||||
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
|
||||
|
||||
If you do not want to install the desktop app you can just install the command
|
||||
line executable. This one runs on more operating systems (OSX, Linux and
|
||||
Windows) but the installation is a bit more involved.
|
||||
If you do not want to install the desktop app then you can just install the command
|
||||
line executable. This runs on more operating systems (OSX, Linux and Windows) but
|
||||
the installation is a bit more involved.
|
||||
|
||||
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`
|
||||
can get you this on OS X and Ubuntu respectively, on Windows do `choco
|
||||
install imagemagick`, which requires [chocolatey :ext](https://chocolatey.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:
|
||||
|
||||
```
|
||||
|
@ -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'))
|
||||
```
|
||||
|
||||
Alternatively you can manually install it with `virtualenv` if you know
|
||||
how that works:
|
||||
## pip
|
||||
|
||||
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
|
||||
|
@ -62,6 +65,12 @@ $ . venv/bin/activate
|
|||
$ 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
|
||||
|
||||
If you want to install the development version of Lektor you can do so. It's
|
||||
|
|
|
@ -108,10 +108,10 @@ class HelloWorldPlugin(Plugin):
|
|||
|
||||
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
|
||||
get a list with `lektor plugins`:
|
||||
get a list with `lektor plugins list`:
|
||||
|
||||
```
|
||||
$ lektor plugins
|
||||
$ lektor plugins list
|
||||
hello-world: Hello World
|
||||
This is a demo plugin for testing purposes.
|
||||
path: /Users/john/demo/packages/hello-world
|
||||
|
|
|
@ -17,10 +17,16 @@ project:
|
|||
this plugin embeds disqus comments into your website.
|
||||
* [webpack-support :ext](https://github.com/lektor/lektor-webpack-support):
|
||||
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
|
||||
you can [edit this page on github
|
||||
:ext](https://github.com/lektor/lektor-website/edit/master/content/docs/plugins/list/contents.lr)
|
||||
and send a pull request.
|
||||
These are unofficial plugins. This list is moderated and updated
|
||||
regularly, but they still aren't developed by the authors of Lektor,
|
||||
so they might not keep pace with development on Lektor.
|
||||
|
||||
* [s3 :ext](https://github.com/spenczar/lektor-s3):
|
||||
allows deployment of websites to S3 buckets
|
||||
|
|
|
@ -87,7 +87,7 @@ but are contained within a field of a model.
|
|||
### `packages/`
|
||||
|
||||
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/`
|
||||
|
||||
|
|
Before Width: | Height: | Size: 209 KiB After Width: | Height: | Size: 118 KiB |
|
@ -50,7 +50,7 @@ $ lektor server
|
|||
```
|
||||
|
||||
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
|
||||
they change.
|
||||
|
|
Before Width: | Height: | Size: 241 KiB After Width: | Height: | Size: 157 KiB |
|
@ -6,8 +6,8 @@ sort_key: 20
|
|||
---
|
||||
body:
|
||||
|
||||
When it comes to creating websites, there is a ludicrous amount of tools available.
|
||||
They range from full blown content management solutions like Drupal over
|
||||
When it comes to creating websites, there is a ludicrous number of tools available.
|
||||
They range from full-blown content management solutions like Drupal to
|
||||
desktop solutions like Google Web Designer to Cloud Hosted Website solutions
|
||||
like WIX to more programmer focused approaches like Jekyll which generate
|
||||
websites out of templates and markdown files.
|
||||
|
@ -17,31 +17,31 @@ websites out of templates and markdown files.
|
|||
## Lektor is Static
|
||||
|
||||
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
|
||||
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
|
||||
or content distribution platform like S3 with CloudFront.
|
||||
server), and generates static HTML that can be uploaded to any web server or
|
||||
content distribution platform like S3 with CloudFront.
|
||||
|
||||
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
|
||||
come for free. It needs server resources and because program code is 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
|
||||
of traffic a static website will stay up for longer on the same server than
|
||||
a dynamic one that needs to execute code.
|
||||
more times than they will be updated. This is crucial because dynamic content
|
||||
does not come for free. It needs server resources and because program code is
|
||||
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 of
|
||||
traffic a static website will stay up for longer on the same server than a
|
||||
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
|
||||
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">
|
||||
|
||||
## Lektor is a CMS
|
||||
|
||||
However Lektor also takes from content management systems like WordPress
|
||||
and provides a flexible browser based admin interface from which you can
|
||||
edit your website's contents. Unlike traditional CMS solutions however it
|
||||
However, Lektor also takes from content management systems like WordPress
|
||||
and provides a flexible browser-based admin interface from which you can
|
||||
edit your website's contents. Unlike traditional CMS solutions, however, it
|
||||
runs entirely on your own computer.
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
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
|
||||
|
|
Before Width: | Height: | Size: 160 KiB After Width: | Height: | Size: 101 KiB |
Before Width: | Height: | Size: 200 KiB After Width: | Height: | Size: 135 KiB |
Before Width: | Height: | Size: 237 KiB After Width: | Height: | Size: 130 KiB |
Before Width: | Height: | Size: 460 KiB After Width: | Height: | Size: 433 KiB |
Before Width: | Height: | Size: 237 KiB After Width: | Height: | Size: 135 KiB |
Before Width: | Height: | Size: 331 KiB After Width: | Height: | Size: 219 KiB |
Before Width: | Height: | Size: 299 KiB After Width: | Height: | Size: 261 KiB |
Before Width: | Height: | Size: 262 KiB After Width: | Height: | Size: 240 KiB |
BIN
content/logo.png
Before Width: | Height: | Size: 294 KiB After Width: | Height: | Size: 175 KiB |
Before Width: | Height: | Size: 306 KiB After Width: | Height: | Size: 168 KiB |
Before Width: | Height: | Size: 294 KiB After Width: | Height: | Size: 170 KiB |
Before Width: | Height: | Size: 270 KiB After Width: | Height: | Size: 152 KiB |
|
@ -6,23 +6,16 @@ button_label = [[flag]]
|
|||
label = Image
|
||||
type = select
|
||||
source = record.attachments.images
|
||||
width = 2/4
|
||||
width = 3/4
|
||||
|
||||
[fields.height]
|
||||
label = Height
|
||||
type = select
|
||||
choices = half, full, 500, 300
|
||||
choice_labels = Half, Full, 500px, 300px
|
||||
choices = 500, 300
|
||||
choice_labels = 500px, 300px
|
||||
default = 300
|
||||
width = 1/4
|
||||
|
||||
[fields.class]
|
||||
label = Class
|
||||
type = select
|
||||
choices = dark
|
||||
choice_labels = Dark
|
||||
width = 1/4
|
||||
|
||||
[fields.contents]
|
||||
label = Contents
|
||||
type = html
|
||||
|
|
|
@ -28,16 +28,12 @@ default = yes
|
|||
checkbox_label = Show comment box
|
||||
width = 1/4
|
||||
|
||||
[fields.body]
|
||||
label = Body
|
||||
type = markdown
|
||||
|
||||
[fields.type]
|
||||
label = Technical Type
|
||||
type = select
|
||||
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
|
||||
choice_labels = Class, Function, Method, Property, Operator, Filter, Commandlet, Event, Field Type
|
||||
choices = class, function, method, property, operator, filter, cmdlet, event, type, sysfield
|
||||
choice_labels = Class, Function, Method, Property, Operator, Filter, Commandlet, Event, Field Type, System Field
|
||||
width = 1/2
|
||||
|
||||
[fields.module]
|
||||
|
@ -57,3 +53,11 @@ description = An optional signature for a type.
|
|||
label = Template Variable
|
||||
type = string
|
||||
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
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
dist
|
||||
build
|
||||
*.pyc
|
||||
*.pyo
|
||||
*.egg-info
|
|
@ -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)
|
|
@ -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',
|
||||
]
|
||||
}
|
||||
)
|
|
@ -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
|
|
@ -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',
|
||||
]
|
||||
}
|
||||
)
|
|
@ -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
|
|
@ -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',
|
||||
]
|
||||
)
|
|
@ -1,8 +1,5 @@
|
|||
{% set image = record.attachments.get(this.image) %}
|
||||
<div class="banner{% if this.class %} banner-{{ this.class }}{% endif %}" style="background-image: url({{ image|url
|
||||
}}); height: {{ {
|
||||
'full': image.height,
|
||||
'half': image.height / 2,
|
||||
}.get(this.height, this.height) }}px">{% if this.contents %}
|
||||
<div class="banner banner-{{ this.height }}" style="background-image: url({{ image|url
|
||||
}})">{% if this.contents %}
|
||||
{{ this.contents }}
|
||||
{% endif %}</div>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<div class="slideshow-wrapper">
|
||||
<div class="slideshow">
|
||||
<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">
|
||||
{% for slide in this.slides.blocks %}
|
||||
|
|
|
@ -33,21 +33,35 @@
|
|||
<div class="col-sm-9 doc-styling">
|
||||
{{ get_doc_header(this) }}
|
||||
|
||||
<ul class=page-meta>
|
||||
{% 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' %}
|
||||
<p class="type-info">Property of {{ get_doc_link(this.parent) }}
|
||||
<li>Property of {{ get_doc_link(this.parent) }}
|
||||
{% elif this.type == 'operator' %}
|
||||
<p class="type-info">Operator of {{ get_doc_link(this.parent) }}
|
||||
<li>Operator of {{ get_doc_link(this.parent) }}
|
||||
{% endif %}
|
||||
{% 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
|
||||
}}"><code>{{ this.template_var }}</code></a>
|
||||
{% endif %}
|
||||
{% if this.version_added %}
|
||||
<li>New in Lektor Version <em>{{ this.version_added }}</em>
|
||||
{% endif %}
|
||||
</ul>
|
||||
|
||||
{{ 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 %}
|
||||
<div class="child-pages">
|
||||
{% for cols in this.children|batch(2) %}
|
||||
|
|
|
@ -56,6 +56,8 @@
|
|||
><i class="fa fa-bug"></i></a>
|
||||
<a href="https://twitter.com/getlektor" title="Find Lektor on Twitter"
|
||||
><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 %}
|
||||
<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>
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<i class="glyphicon glyphicon-console"></i>
|
||||
{%- elif page.type == 'event' -%}
|
||||
<i class="glyphicon glyphicon-flash"></i>
|
||||
{%- elif page.type == 'type' -%}
|
||||
{%- elif page.type == 'type' or page.type == 'sysfield' -%}
|
||||
<i class="glyphicon glyphicon-pencil"></i>
|
||||
{%- else -%}
|
||||
<i class="glyphicon glyphicon-list-alt"></i>
|
||||
|
|
|
@ -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() {
|
||||
let buttons = $('.download-btn');
|
||||
if (buttons.length <= 0) {
|
||||
|
@ -143,6 +166,7 @@ function hideThingsForWindows() {
|
|||
}
|
||||
|
||||
$(function() {
|
||||
initBadges();
|
||||
initDownloadButton();
|
||||
initInstallRow();
|
||||
initGoogleSearch();
|
||||
|
|
|
@ -103,7 +103,7 @@ div.slideshow {
|
|||
height: auto;
|
||||
overflow: auto;
|
||||
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;
|
||||
|
||||
div.slideshow-inner {
|
||||
|
@ -259,14 +259,24 @@ div.banner {
|
|||
margin: 15px 0;
|
||||
background-size: cover;
|
||||
background-position: center center;
|
||||
background-color: $lektor-header-bg;
|
||||
|
||||
&:first-child {
|
||||
margin-top: 0;
|
||||
box-shadow: 0 4px 10px fade-out($gray, 0.8);
|
||||
}
|
||||
|
||||
&.banner-dark {
|
||||
background-color: $lektor-header-bg;
|
||||
&.banner-500 {
|
||||
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;
|
||||
}
|
||||
p.type-info + p.type-info {
|
||||
margin-top: 0;
|
||||
margin: 0;
|
||||
padding: 0 0 0 30px;
|
||||
line-height: 1.4;
|
||||
|
||||
> li {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
&:last-child {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
em {
|
||||
background: #eee;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
table {
|
||||
|
@ -314,6 +337,10 @@ div.doc-styling {
|
|||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
tr {
|
||||
background: white;
|
||||
}
|
||||
|
||||
tr:nth-child(odd) {
|
||||
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 */
|
||||
div.doc-styling div.gsc-control-cse {
|
||||
font-family: $font-family-base!important;
|
||||
|
|