django-scribbler is an application for managing snippets of text for a Django website. Similar projects include django-flatblocks, django-chunks and django-pagelets. This project attempts to take some of the best concepts from those previous projects as well as focus on giving the users instant feedback inspired by Bret Victor’s Inventing on Principle talk.
django-scribbler currently requires Django 2.0, 2.1 or 2.2 and Python >= 3.4. Older versions of django-scribbler may support older versions of Django and Python.
To install from PyPi:
pip install django-scribbler
Note
If you need to run an unreleased version from the repository, see the Contributing Guide for additional instructions.
Documentation on using django-scribbler is available on Read The Docs.
If you think you’ve found a bug or are interested in contributing to this project check out django-scribbler on Github. A full contributing guide can be found in the online documentation.
If you are interested in translating django-scribbler into your native language you can join the Transifex project.
Development sponsored by Caktus Consulting Group, LLC.
An example project is included that demonstrates basic usage of django-scribbler.
Check out the source code and see the README.rst
file in the example
directory
for more information.
Below are the basic steps need to get django-scribbler integrated into your Django project.
django-scribbler should be installed using pip
:
$ pip install django-scribbler
Note
If you need to run an unreleased version from the repository, see Contributing Guide for additional instructions.
You need to include scribbler
to your installed apps. django-scribbler requires
django.contrib.auth
which in turn requires django.contrib.sessions
which are enabled in Django by default. You will also need to include a context processor
to include the current request in the template context. This is included by default
in Django 1.8+ when using the startproject
command.
INSTALLED_APPS = (
# Required contrib apps
'django.contrib.auth',
'django.contrib.sessions',
# Other installed apps would go here
'scribbler',
)
...
TEMPLATES = [ # example config untill 'context_processors' your config maydiffer
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
# add required context processors here:
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
# Other context processors would go here
],
'debug': False,
},
},
],
Django 1.8+ also supports custom template engines but this is not supported at the moment by django-scribbler (only the Django and Jinja2 template engines are supported).
For the context processor to have any effect you need to make sure that the template is rendered using a RequestContext. This is done for you with the render shortcut.
django-scribbler aggressively caches the scribble content. By default the scribble
content is cached for 12 hours. You have the option to configure this cache timeout
with the SCRIBBLER_CACHE_TIMEOUT
setting. The value should be the timeout in
seconds.
You should include the scribbler urls in your root url patterns.
urlpatterns = [
# Other url patterns would go here
url(r'^scribbler/', include('scribbler.urls')),
]
You’ll need to create the necessary database tables for storing scribble content. To run migrations call:
python manage.py migrate scribbler
To edit scribbles on the front-end users must have the scribbler.add_scribble
and scribbler.change_scribble
permissions. You can configure uses to have
these permissions through the users section of the Django admin. Superusers have
all of these permissions by default.
Similarly, to edit fields from models on the front-end, users must have “change” permission for the models being edited. Again these permissions can be configured through the users section of the Django admin.
django-scribbler includes both CSS and JS resources which need to be included in your
templates to handle the front-end content management. Since you may want to include
scribbles on any page on your site these should be included in your base template <head>
.
<link rel="stylesheet" href="{% static 'scribbler/css/scribbler.css' %}">
<script src="{% static 'scribbler/js/scribbler-min.js' %}"></script>
This uses Browserify to load the additional JS resources. The front-end
editor uses CodeMirror (currently using v5.10) which is included in the distribution.
Both Browserify and CodeMirror are available a MIT-style license compatible with
this project’s BSD license. You can find the license files included in
scribbler/static/scribbler/libs/
.
You are now ready to place the scribble content blocks throughout your templates.
This is done with the scribble
block tag. The basic usage of the tag takes
one argument which is the slug name for the scribble, and contains the default
content for the scribble.
Slugs must be unique per url/slug pair. That means you cannot use the same slug more than once in the template, but you can use the same slug in different templates, as long as they are rendered on different urls.
{% load scribbler_tags %}
{% scribble 'header' %}
<p>Blip {% now 'Y' %} {{ STATIC_URL|upper }}</p>
{% endscribble %}
The content inside the block is the default content that will be rendered if a matching scribble in the database is not found.
The scribble
tag can take an optional argument which allows for defining
shared scribbles.
{% load scribbler_tags %}
{% scribble 'header' 'shared' %}
<p>Blip {% now 'Y' %} {{ STATIC_URL|upper }}</p>
{% endscribble %}
The second argument defines a lookup vector to a shared scribble. This overrides the url portion of the url/slug pair, and allows for reuse across multiple templates.
In other words, ordinarily even scribbles with the same slug are considered different when they occur on pages with different URLs, but if you also give them the same second argument, they will be considered the same - they will share the same content.
Note
Scribble content can be any valid Django template. However the content does
not include all of the context of the template. Only the context provided
by the set of context_processors
from the TEMPLATES
configuration.
A second scribbler tag, scribble_field
, allows for editing fields of model instances.
For example, suppose you have a DaysLog
model with a field named happenings
. Suppose
an instance of this model is passed into your template in the template variable days_log
.
Then the happenings
field of this DaysLog
instance can be displayed and edited on the
page by including this scribble_field
template tag in the template for the page:
{% load scribbler_tags %}
{% scribble_field days_log 'happenings' %}
Note
The logged-in user must have “change” permission for the model in order for the model instance to be editable on the page.
That should be enough to get you up and running with django-scribbler.
django-scribbler makes use of CodeMirror to create a powerful client-side editor. We’ve added a couple features to make it easier when working with Django templates.
When using the editor, you can inspect the current context by starting a variable
node with {{
and hitting tab. As noted in the quick start introduction,
scribble content can be any valid Django template. The context provided when
rendering the scribble includes anything added by the set of
TEMPLATE_CONTEXT_PROCESSORS
. This would include STATIC_URL
, MEDIA_URL
,
LANGUAGE_CODE
, the current user
and others. Developers may choose to add
context processors to include additional content for rendering scribbles.
Similar to how the editor can tab-complete the context variables, you can tab
complete template tags when {%
has been opened. The built-in filters can
be tab-completed when the pipe |
character is detected inside of a variable node.
Currently this will only complete the built-in tags and filter and will not include any
additional tags or filters which might be added by loading additional libraries inside the scribble.
While editing the scribble content, the editor will periodically save the current editor content as a draft. These drafts are saved on the client side using local storage (if supported by the browser) or a cookie. While that means you won’t be able to see or use these drafts in another browser, it does mean that you work will not be lost if there is a failure on the server while saving changes or making edits. When the editor is opened it will restore any draft that is found. There is the option to discard a working draft. This will load the current scribble content into the editor.
Sometimes scribbles are rather long and it is useful to have more screen area to see the text. While the editor is in focus you may press F11 to view the scribble in full-screen mode. To deactivate full-screen mode press either F11 or ESC.
It is possible that plugins may be added back in the future, but as of right now there is no working plugin feature. All following documentation only pertains to versions 0.6.0 and earlier.
django-scribbler editor has some nice features like a live preview, auto-saving drafts and tab completion of template tags and template context. If you find yourself wanting to extend the functionality of the editor or top menu you can write a plugin.
Client-side plugins to be added to a scribbler/js/plugins
folder inside of
static files folder. If you are writing this plugin for a reusable application
then it would live inside of the app’s static
folder. The plugin name
will be the name of the .js file. For example we might create a demo
plugin
by adding a scribbler/js/plugins/demo.js
inside of our app static
folder.
django-scribbler uses RequireJS to load its Javascript requirements. Since this code is loaded in a closure, plugins need to be written in the AMD format. The basic format is:
define(function () {
function plugin(editor, menu) {
// Plugin code goes here...
}
return plugin;
});
This has an advantage in that the plugin code can declare requirements as well as take advantage of existing modules used by the scribbler code. For instance if your plugin requires jQuery you can define the requirement:
define(['jquery'], function ($) {
function plugin(editor, menu) {
// Plugin code goes here...
}
return plugin;
});
The plugin code itself should return a function which takes two arguments: editor
and menu
. Each are the current instance of the editor and the menu respectively.
Within the plugin you can add additional controls or event bindings. The APIs for
both the editor and the menu are given below.
Note
The plugins are executed after the editor and menu have been initialized but they are loaded asynchronously. That means the editor and menu may be fully rendered before the plugins are executed.
Plugins are enable by listing them in a data-scribbler-plugins
attribute on the
script tag:
<script data-scribbler-plugins="themes"
data-main="{{ STATIC_URL }}scribbler/js/scribbler{% if not debug %}-min{% endif %}"
src="{{ STATIC_URL }}scribbler/libs/require.js"></script>
If mutliple plugins used then they should be comma seperated as in
data-scribbler-plugins="themes,other"
.
Note
Since the plugins are loaded asynchronously they might not load in the same order they are listed. Plugins should be written and designed with that limitation in mind.
As noted above you can use the define
call to load additional dependencies/libraries
for your plugin from the set of libraries used by django-scribbler. The available libraries
are:
The editor
passed in the plugin is an instance of the ScribbleEditor
defined
in scribbler/js/scribbler-editor.js
. Below is a list of some of the most relevant
functions and properties for controlling the editor.
editor.
scribbles
¶This is a jQuery object containing all of the scribble divs available on the page for editting.
A jQuery object for the div wrapping all of the editor button controls (Save, Save Draft, Discard Draft, Close). If you want to add additional controls they should be appended here.
editor.
editor
¶editor.editor
is the instance of the CodeMirror editor. You can manipulate this
object to change the options with editor.editor.setOption
. See the CodeMirror
usage manual for available options: http://codemirror.net/doc/manual.html
editor.
open
(scribble)¶Opens the editor to edit the given scribble.
editor.
close
()¶Closes the editor.
editor.
submitPreview
(force)¶Submits the current editor content to render the live preview. By default this
will not submit if the editor is currently in the process of rendering a preview.
Passing true
into the call will force the submission.
editor.
submitSave
()¶Submits the editor content to save the current scribble content. By default the save will not be submitted if the last preview was not valid.
editor.
getFormData
()¶Prepares the current form data for preview/save submission. If you want to pass additional data to the server your plugin could extend this function.
editor.
createDraft
()¶Saves the current editor content as a local draft.
editor.
restoreDraft
()¶Restores the editor content from the last saved draft if available.
editor.
deleteDraft
()¶Discards last saved draft.
editor.
setStatus
(msg)¶Displays a status message to the user in the header of the editor.
editor.
destroy
()¶Removes the editor from the DOM and unbinds all event handling.
There are a number of ways to contribute to django-scribbler. If you are interested in making django-scribbler better then this guide will help you find a way to contribute.
You can contribute to the project by submitting bug reports, feature requests or documentation updates through the Github issues.
We are working towards translating django-scribbler into different languages. There are only a few strings to translate so it is a great way to be involved with the project. The translations are managed through Transifex. Please do not submit translate requests/updates to the Github repo.
You can clone the repository from Github:
git clone https://github.com/caktus/django-scribbler.git
However this checkout will be read only. If you want to contribute code you should create a fork and clone your fork. You can then add the main repository as a remote:
git clone git@github.com:<your-username>/django-scribbler.git
cd django-scribbler
git remote add upstream git://github.com/caktus/django-scribbler.git
git fetch upstream
django-scribbler requires a few static libraries which are not included in the repository. Before beginning development you should make sure you have these libraries with:
make fetch-static-libs
When making changes to the code, either fixing bugs or adding features, you’ll want to run the tests to ensure that you have not broken any of the existing functionality. With the code checked out and Django installed you can run the tests via:
python setup.py test
or:
python runtests.py
Note that the tests require the mock library.
To test against multiple versions of Django you can use install and use tox>=1.4
. The
tox
command will run the tests against supported versions of Django and Python.:
# Build all environments
tox
# Build a single environment
tox -e py37-2.2.X
Building all environments will also build the documentation. More on that in the next section.
The JS plugins are tested using the QUnit <http://qunitjs.com/> testing framework. You can
run the tests by opening scribbler\tests\qunit\index.html
in your browser. You can also
run the tests using the PhantomJS <http://phantomjs.org/> headless runner. First install
PhantomJS from NPM (requires at least 1.6):
# Install phantomjs from the NPM package
npm install phantomjs -g
# Run QUnit tests
phantomjs scribbler/tests/qunit/runner.js scribbler/tests/qunit/index.html
We’ve added a make command which you can use as well:
make test-js
This project aims to have a minimal core with hooks for customization. That makes documentation an important part of the project. Useful examples and notes on common use cases are a great way to contribute and improve the documentation.
The docs are written in ReST and built using Sphinx. As noted above you can use tox to build the documentation or you can build them on their own via:
tox -e docs
or:
make html
from inside the docs/
directory.
The CSS used by django-scribbler is built using LESS. No changes
should be made to the scribbler.css
directly. Instead changes should be made to the scribbler.less
file. After changes are made to scribbler.less
you can create the new compressed CSS with the
Node based complier. In addition, this inlines the required codemirror.css
:
make build-css
The example project uses the client-side LESS compiler to make local development easier.
While it is not often needed for local development, the final released JS is bundled and minified
using Browserify and UglifyJS2. To build bundle-min.js
you should
have the optimizer installed and run:
make build-js
Code contributions should follow the PEP8 and Django contributing style standards. Please note that these are only guidelines. Overall code consistency and readability are more important than strict adherence to these guides.
The Javascript is configured for some basic JSHint checks. Changes to the Javascript should pass without errors. You can check the Javascript file on the command line with Node based CLI tool:
# Install jshint from the NPM package
npm install jshint -g
# Check the scribbler JS
jshint scribbler/static/scribbler/js/
This can also be done with the make
command:
make lint-js
The easiest way to contribute code or documentation changes is through a pull request. For information on submitting a pull request you can read the Github help page https://help.github.com/articles/using-pull-requests.
Pull requests are a place for the code to be reviewed before it is merged. This review will go over the coding style as well as if it solves the problem intended and fits in the scope of the project. It may be a long discussion or it might just be a simple thank you.
Not necessarily every request will be merged but you should not take it personally if you change is not accepted. If you want to increase the chances of your change being incorporated then here are some tips.
You should also feel free to ask for help writing tests or writing documentation if you aren’t sure how to go about it.
Since the built CSS, JS and other static dependencies are not included in the repository, it is not possible to install django-scribbler directly from Github. If you want to install and unstable version of django-scribbler you have a few options.
Warning
While we try to keep the master
branch stable, there may be bugs or unfinished work there. It
is recommended that you use a stable release of django-scribbler when possible.
The step overview for installing from a local build is:
From the command line this would be:
git clone git://github.com/caktus/django-scribbler.git
cd django-scribbler
make fetch-static-libs build-css build-js
Installing from a local build is probably a reasonable solution for a single person wanting to test out the current master or a feature branch in a large project. However, it isn’t a good solution if you want to deploy this to a larger testing environment or multiple computers. The basic steps are more or less the same:
From the command line this would be:
git clone git://github.com/caktus/django-scribbler.git
cd django-scribbler
make fetch-static-libs build-css build-js
python setup.py sdist
This will create a django-scribbler-X.X.X.tar.gz
inside a dist/
directory where
X.X.X
is the current scribbler.__version__
. This tar file would then be distributed
using your favorite file hosting service (S3, Dropbox, etc). You can then install by using pip
:
pip install http://path-to-hostedfile/django-scribbler-X.X.X.tar.gz
Release and change history for django-scribbler
The release removed the use of RequireJS for bundling the required assets and instead uses Browserify to create single required JS file. Updating from a previous version requires changing how the JS file is included.
<script data-main="{% static 'scribbler/js/scribbler-min' %}" src="{% static 'scribbler/libs/require.js' %}"></script>
should be updated to
<script src="{% static 'scribbler/js/scribbler-min.js' %}"></script>
This release fixes some lingering issues with Django 1.8 support and integrates Wheel support and features from the latest versions of Tox.
This release includes a major refactor of the JS code and adds support for writing client-side plugins for customizing the editor.
The static dependencies (RequireJS, CodeMirror and jQuery) were originally included in the repository but have been removed. These are still included in the final distribution. However, if you installing django-scribbler directly from git these will no longer be available. See the contributing guide for more information on building/installing an unstable version.
The length of the slug field has been reduced to fix problems with the unique contraint on MySQL. Upgrading requires running a migration:
manage.py migrate scribbler
The editor now saves drafts on the client side by default. Python 3 support is added when using the lastest Django master. There is also some additional documentation.
A unique constraint was added and upgrading from v0.1 does require a migration:
manage.py migrate scribbler