Steve Piercy
2015-05-26 5fdc226d5d72e236324773812f6fe3663ebd48c7
Merge pull request #1791 from stevepiercy/1.6-branch

- clean up and make defininingviews consistent between two wiki tutor…
8 files deleted
3 files added
15 files modified
1632 ■■■■■ changed files
docs/tutorials/wiki/definingviews.rst 287 ●●●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/authorization/setup.py 4 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/authorization/tutorial/templates/mytemplate.pt 127 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/basiclayout/setup.py 4 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/basiclayout/tutorial/templates/mytemplate.pt 2 ●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/models/setup.py 4 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/models/tutorial/templates/mytemplate.pt 2 ●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/tests/setup.py 4 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/tests/tutorial/templates/mytemplate.pt 127 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/views/setup.py 4 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/views/tutorial/static/favicon.ico patch | view | raw | blame | history
docs/tutorials/wiki/src/views/tutorial/static/footerbg.png patch | view | raw | blame | history
docs/tutorials/wiki/src/views/tutorial/static/headerbg.png patch | view | raw | blame | history
docs/tutorials/wiki/src/views/tutorial/static/ie6.css 8 ●●●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/views/tutorial/static/middlebg.png patch | view | raw | blame | history
docs/tutorials/wiki/src/views/tutorial/static/pylons.css 372 ●●●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/views/tutorial/static/pyramid-16x16.png patch | view | raw | blame | history
docs/tutorials/wiki/src/views/tutorial/static/pyramid-small.png patch | view | raw | blame | history
docs/tutorials/wiki/src/views/tutorial/static/pyramid.png patch | view | raw | blame | history
docs/tutorials/wiki/src/views/tutorial/static/theme.css 154 ●●●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/views/tutorial/static/theme.min.css 1 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/views/tutorial/static/transparent.gif patch | view | raw | blame | history
docs/tutorials/wiki/src/views/tutorial/templates/edit.pt 117 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/views/tutorial/templates/mytemplate.pt 130 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/views/tutorial/templates/view.pt 122 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki2/definingviews.rst 163 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki/definingviews.rst
@@ -17,7 +17,7 @@
   interchangeably as necessary. In :term:`traversal` based applications,
   URLs are mapped to a context :term:`resource`, and since our
   :term:`resource tree` also represents our application's
   "domain model", we're often interested in the context, because
   "domain model", we're often interested in the context because
   it represents the persistent storage of our application.  For
   this reason, in this tutorial we define views as callables that
   accept ``context`` in the callable argument list.  If you do
@@ -35,35 +35,80 @@
The view code in our application will depend on a package which is not a
dependency of the original "tutorial" application.  The original "tutorial"
application was generated by the ``pcreate`` command; it doesn't know
about our custom application requirements.  We need to add a dependency on
the ``docutils`` package to our ``tutorial`` package's ``setup.py`` file by
assigning this dependency to the ``install_requires`` parameter in the
``setup`` function.
about our custom application requirements.
Our resulting ``setup.py`` should look like so:
We need to add a dependency on the ``docutils`` package to our ``tutorial``
package's ``setup.py`` file by assigning this dependency to the ``requires``
parameter in the ``setup()`` function.
Open ``tutorial/setup.py`` and edit it to look like the following:
.. literalinclude:: src/views/setup.py
   :linenos:
   :emphasize-lines: 20
   :language: python
.. note:: After these new dependencies are added, you will need to
   rerun ``python setup.py develop`` inside the root of the
   ``tutorial`` package to obtain and register the newly added
   dependency package.
Only the highlighted line needs to be added.
Adding View Functions
=====================
Running ``setup.py develop``
============================
We're going to add four :term:`view callable` functions to our ``views.py``
module.  One view named ``view_wiki`` will display the wiki itself (it will
answer on the root URL), another named ``view_page`` will display an
individual page, another named ``add_page`` will allow a page to be added,
and a final view named ``edit_page`` will allow a page to be edited.
Since a new software dependency was added, you will need to run ``python
setup.py develop`` again inside the root of the ``tutorial`` package to obtain
and register the newly added dependency distribution.
Make sure your current working directory is the root of the project (the
directory in which ``setup.py`` lives) and execute the following command.
On UNIX:
.. code-block:: text
   $ cd tutorial
   $ $VENV/bin/python setup.py develop
On Windows:
.. code-block:: text
   c:\pyramidtut> cd tutorial
   c:\pyramidtut\tutorial> %VENV%\Scripts\python setup.py develop
Success executing this command will end with a line to the console something
like::
   Finished processing dependencies for tutorial==0.0
Adding view functions in ``views.py``
=====================================
It's time for a major change.  Open ``tutorial/tutorial/views.py`` and edit it
to look like the following:
.. literalinclude:: src/views/tutorial/views.py
   :linenos:
   :language: python
We added some imports and created a regular expression to find "WikiWords".
We got rid of the ``my_view`` view function and its decorator that was added
when we originally rendered the ``zodb`` scaffold.  It was only an example and
isn't relevant to our application.
Then we added four :term:`view callable` functions to our ``views.py``
module:
* ``view_wiki()`` - Displays the wiki itself. It will answer on the root URL.
* ``view_page()`` - Displays an individual page.
* ``add_page()`` - Allows the user to add a page.
* ``edit_page()`` - Allows the user to edit a page.
We'll describe each one briefly in the following sections.
.. note::
  There is nothing special about the filename ``views.py``.  A project may
  have many view callables throughout its codebase in arbitrarily-named
  have many view callables throughout its codebase in arbitrarily named
  files.  Files implementing view callables often have ``view`` in their
  filenames (or may live in a Python subpackage of your application package
  named ``views``), but this is only by convention.
@@ -71,44 +116,55 @@
The ``view_wiki`` view function
-------------------------------
Here is the code for the ``view_wiki`` view function and its decorator, which
will be added to ``views.py``:
Following is the code for the ``view_wiki`` view function and its decorator:
.. literalinclude:: src/views/tutorial/views.py
   :lines: 12-14
   :lineno-start: 12
   :linenos:
   :language: python
The ``view_wiki`` function will be configured to respond as the default view
callable for a Wiki resource.  We'll provide it with a ``@view_config``
decorator which names the class ``tutorial.models.Wiki`` as its context.
This means that when a Wiki resource is the context, and no :term:`view name`
exists in the request, this view will be used.  The view configuration
associated with ``view_wiki`` does not use a ``renderer`` because the view
callable always returns a :term:`response` object rather than a dictionary.
No renderer is necessary when a view returns a response object.
.. note:: In our code, we use an *import* that is *relative* to our package
    named ``tutorial``, meaning we can omit the name of the package in the
    ``import`` and ``context`` statements. In our narrative, however, we refer
    to a *class* and thus we use the *absolute* form, meaning that the name of
    the package is included.
The ``view_wiki`` view callable always redirects to the URL of a Page
resource named "FrontPage".  To do so, it returns an instance of the
``view_wiki()`` is the :term:`default view` that gets called when a request is
made to the root URL of our wiki.  It always redirects to an URL which
represents the path to our "FrontPage".
We provide it with a ``@view_config`` decorator which names the class
``tutorial.models.Wiki`` as its context. This means that when a Wiki resource
is the context and no :term:`view name` exists in the request, then this view
will be used.  The view configuration associated with ``view_wiki`` does not
use a ``renderer`` because the view callable always returns a :term:`response`
object rather than a dictionary. No renderer is necessary when a view returns
a response object.
The ``view_wiki`` view callable always redirects to the URL of a Page resource
named "FrontPage".  To do so, it returns an instance of the
:class:`pyramid.httpexceptions.HTTPFound` class (instances of which implement
the :class:`pyramid.interfaces.IResponse` interface like
:class:`pyramid.response.Response` does).
:meth:`pyramid.request.Request.resource_url` constructs a URL to the
the :class:`pyramid.interfaces.IResponse` interface, like
:class:`pyramid.response.Response` does). It uses the
:meth:`pyramid.request.Request.route_url` API to construct an URL to the
``FrontPage`` page resource (i.e., ``http://localhost:6543/FrontPage``), and
uses it as the "location" of the HTTPFound response, forming an HTTP
uses it as the "location" of the ``HTTPFound`` response, forming an HTTP
redirect.
The ``view_page`` view function
-------------------------------
Here is the code for the ``view_page`` view function and its decorator, which
will be added to ``views.py``:
Here is the code for the ``view_page`` view function and its decorator:
.. literalinclude:: src/views/tutorial/views.py
   :lines: 16-33
   :lineno-start: 16
   :linenos:
   :language: python
The ``view_page`` function will be configured to respond as the default view
of a Page resource.  We'll provide it with a ``@view_config`` decorator which
The ``view_page`` function is configured to respond as the default view
of a Page resource.  We provide it with a ``@view_config`` decorator which
names the class ``tutorial.models.Page`` as its context.  This means that
when a Page resource is the context, and no :term:`view name` exists in the
request, this view will be used.  We inform :app:`Pyramid` this view will use
@@ -116,9 +172,9 @@
The ``view_page`` function generates the :term:`reStructuredText` body of a
page (stored as the ``data`` attribute of the context passed to the view; the
context will be a Page resource) as HTML.  Then it substitutes an HTML anchor
for each *WikiWord* reference in the rendered HTML using a compiled regular
expression.
context will be a ``Page`` resource) as HTML.  Then it substitutes an HTML
anchor for each *WikiWord* reference in the rendered HTML using a compiled
regular expression.
The curried function named ``check`` is used as the first argument to
``wikiwords.sub``, indicating that it should be called to provide a value for
@@ -133,8 +189,8 @@
containing various view and add links for WikiWords based on the content of
our current page resource.
We then generate an edit URL (because it's easier to do here than in the
template), and we wrap up a number of arguments in a dictionary and return
We then generate an edit URL because it's easier to do here than in the
template, and we wrap up a number of arguments in a dictionary and return
it.
The arguments we wrap into a dictionary include ``page``, ``content``, and
@@ -153,22 +209,23 @@
The ``add_page`` view function
------------------------------
Here is the code for the ``add_page`` view function and its decorator, which
will be added to ``views.py``:
Here is the code for the ``add_page`` view function and its decorator:
.. literalinclude:: src/views/tutorial/views.py
   :lines: 35-50
   :lineno-start: 35
   :linenos:
   :language: python
The ``add_page`` function will be configured to respond when the context
resource is a Wiki and the :term:`view name` is ``add_page``.  We'll provide
it with a ``@view_config`` decorator which names the string ``add_page`` as
its :term:`view name` (via name=), the class ``tutorial.models.Wiki`` as its
context, and the renderer named ``templates/edit.pt``.  This means that when
a Wiki resource is the context, and a :term:`view name` named ``add_page``
The ``add_page`` function is configured to respond when the context resource
is a Wiki and the :term:`view name` is ``add_page``.  We provide it with a
``@view_config`` decorator which names the string ``add_page`` as its
:term:`view name` (via ``name=``), the class ``tutorial.models.Wiki`` as its
context, and the renderer named ``templates/edit.pt``.  This means that when a
Wiki resource is the context, and a :term:`view name` named ``add_page``
exists as the result of traversal, this view will be used.  We inform
:app:`Pyramid` this view will use the ``templates/edit.pt`` template file as
a ``renderer``.  We share the same template between add and edit views, thus
:app:`Pyramid` this view will use the ``templates/edit.pt`` template file as a
``renderer``.  We share the same template between add and edit views, thus
``edit.pt`` instead of ``add.pt``.
The ``add_page`` function will be invoked when a user clicks on a WikiWord
@@ -181,7 +238,7 @@
The request :term:`subpath` in :app:`Pyramid` is the sequence of names that
are found *after* the :term:`view name` in the URL segments given in the
``PATH_INFO`` of the WSGI request as the result of :term:`traversal`.  If our
add view is invoked via, e.g. ``http://localhost:6543/add_page/SomeName``,
add view is invoked via, e.g., ``http://localhost:6543/add_page/SomeName``,
the :term:`subpath` will be a tuple: ``('SomeName',)``.
The add view takes the zeroth element of the subpath (the wiki page name),
@@ -198,7 +255,7 @@
``page``, and we'll render the template to a response.
If the view rendering *is* a result of a form submission (if the expression
``'form.submitted' in request.params`` is ``True``), we scrape the page body
``'form.submitted' in request.params`` is ``True``), we grab the page body
from the form data, create a Page object using the name in the subpath and
the page body, and save it into "our context" (the Wiki) using the
``__setitem__`` method of the context. We then redirect back to the
@@ -207,15 +264,16 @@
The ``edit_page`` view function
-------------------------------
Here is the code for the ``edit_page`` view function and its decorator, which
will be added to ``views.py``:
Here is the code for the ``edit_page`` view function and its decorator:
.. literalinclude:: src/views/tutorial/views.py
   :lines: 52-60
   :lineno-start: 52
   :linenos:
   :language: python
The ``edit_page`` function will be configured to respond when the context is
a Page resource and the :term:`view name` is ``edit_page``.  We'll provide it
The ``edit_page`` function is configured to respond when the context is
a Page resource and the :term:`view name` is ``edit_page``.  We provide it
with a ``@view_config`` decorator which names the string ``edit_page`` as its
:term:`view name` (via ``name=``), the class ``tutorial.models.Page`` as its
context, and the renderer named ``templates/edit.pt``.  This means that when
@@ -240,26 +298,16 @@
attribute of the page context.  It then redirects to the default view of the
context (the page), which will always be the ``view_page`` view.
Viewing the Result of all Our Edits to ``views.py``
===================================================
The result of all of our edits to ``views.py`` will leave it looking like
this:
.. literalinclude:: src/views/tutorial/views.py
   :linenos:
   :language: python
Adding Templates
Adding templates
================
The ``view_page``, ``add_page`` and ``edit_page`` views that we've added
reference a :term:`template`.  Each template is a :term:`Chameleon` :term:`ZPT`
template.  These templates will live in the ``templates`` directory of our
tutorial package.  Chameleon templates must have a ``.pt`` extension to be
recognized as such.
reference a :term:`template`.  Each template is a :term:`Chameleon`
:term:`ZPT` template.  These templates will live in the ``templates``
directory of our tutorial package.  Chameleon templates must have a ``.pt``
extension to be recognized as such.
The ``view.pt`` Template
The ``view.pt`` template
------------------------
Create ``tutorial/tutorial/templates/view.pt`` and add the following
@@ -267,20 +315,18 @@
.. literalinclude:: src/views/tutorial/templates/view.pt
   :linenos:
   :language: xml
   :language: html
This template is used by ``view_page()`` for displaying a single
wiki page. It includes:
- A ``div`` element that is replaced with the ``content``
  value provided by the view (rows 45-47).  ``content``
  contains HTML, so the ``structure`` keyword is used
  to prevent escaping it (i.e. changing ">" to ">", etc.)
- A link that points
  at the "edit" URL which invokes the ``edit_page`` view for
  the page being viewed (rows 49-51).
- A ``div`` element that is replaced with the ``content`` value provided by
  the view (lines 36-38).  ``content`` contains HTML, so the ``structure``
  keyword is used to prevent escaping it (i.e., changing ">" to ">", etc.)
- A link that points at the "edit" URL which invokes the ``edit_page`` view
  for the page being viewed (lines 40-42).
The ``edit.pt`` Template
The ``edit.pt`` template
------------------------
Create ``tutorial/tutorial/templates/edit.pt`` and add the following
@@ -288,66 +334,59 @@
.. literalinclude:: src/views/tutorial/templates/edit.pt
   :linenos:
   :language: xml
   :language: html
This template is used by ``add_page()`` and ``edit_page()`` for adding
and editing a wiki page.  It displays
a page containing a form that includes:
This template is used by ``add_page()`` and ``edit_page()`` for adding and
editing a wiki page.  It displays a page containing a form that includes:
- A 10 row by 60 column ``textarea`` field named ``body`` that is filled
  with any existing page data when it is rendered (rows 46-47).
- A submit button that has the name ``form.submitted`` (row 48).
  with any existing page data when it is rendered (line 45).
- A submit button that has the name ``form.submitted`` (line 48).
The form POSTs back to the "save_url" argument supplied
by the view (row 45).  The view will use the ``body`` and
``form.submitted`` values.
The form POSTs back to the ``save_url`` argument supplied by the view (line
43).  The view will use the ``body`` and ``form.submitted`` values.
.. note:: Our templates use a ``request`` object that
   none of our tutorial views return in their dictionary.
   ``request`` is one of several
   names that are available "by default" in a template when a template
   renderer is used.  See :ref:`renderer_system_values` for
   information about other names that are available by default
   when a template is used as a renderer.
.. note:: Our templates use a ``request`` object that none of our tutorial
   views return in their dictionary. ``request`` is one of several names that
   are available "by default" in a template when a template renderer is used.
   See :ref:`renderer_system_values` for information about other names that
   are available by default when a template is used as a renderer.
Static Assets
-------------
Our templates name a single static asset named ``pylons.css``.  We don't need
to create this file within our package's ``static`` directory because it was
provided at the time we created the project. This file is a little too long to
replicate within the body of this guide, however it is available `online
<https://github.com/Pylons/pyramid/blob/master/docs/tutorials/wiki/src/views/tutorial/static/pylons.css>`_.
Our templates name static assets, including CSS and images.  We don't need
to create these files within our package's ``static`` directory because they
were provided at the time we created the project.
This CSS file will be accessed via
e.g. ``/static/pylons.css`` by virtue of the call to
As an example, the CSS file will be accessed via
``http://localhost:6543/static/theme.css`` by virtue of the call to the
``add_static_view`` directive we've made in the ``__init__.py`` file.  Any
number and type of static assets can be placed in this directory (or
subdirectories) and are just referred to by URL.
subdirectories) and are just referred to by URL or by using the convenience
method ``static_url``, e.g.,
``request.static_url('<package>:static/foo.css')`` within templates.
Viewing the Application in a Browser
====================================
We can finally examine our application in a browser (See
:ref:`wiki-start-the-application`).  Launch a browser and visit
each of the following URLs, check that the result is as expected:
each of the following URLs, checking that the result is as expected:
- ``http://localhost:6543/`` invokes the ``view_wiki``
  view.  This always redirects to the ``view_page`` view of the ``FrontPage``
  Page resource.
- ``http://localhost:6543/`` invokes the ``view_wiki`` view.  This always
  redirects to the ``view_page`` view of the ``FrontPage`` Page resource.
- ``http://localhost:6543/FrontPage/`` invokes
  the ``view_page`` view of the front page resource.  This is
  because it's the :term:`default view` (a view without a ``name``) for Page
  resources.
- ``http://localhost:6543/FrontPage/`` invokes the ``view_page`` view of the
  front page resource.  This is because it's the :term:`default view` (a view
  without a ``name``) for Page resources.
- ``http://localhost:6543/FrontPage/edit_page``
  invokes the edit view for the ``FrontPage`` Page resource.
- ``http://localhost:6543/FrontPage/edit_page`` invokes the edit view for the
  ``FrontPage`` Page resource.
- ``http://localhost:6543/add_page/SomePageName``
  invokes the add view for a Page.
- ``http://localhost:6543/add_page/SomePageName`` invokes the add view for a
  Page.
- To generate an error, visit ``http://localhost:6543/add_page`` which
  will generate an ``IndexErrorr: tuple index out of range`` error.
  You'll see an interactive traceback
  facility provided by :term:`pyramid_debugtoolbar`.
- To generate an error, visit ``http://localhost:6543/add_page`` which will
  generate an ``IndexErrorr: tuple index out of range`` error. You'll see an
  interactive traceback facility provided by :term:`pyramid_debugtoolbar`.
docs/tutorials/wiki/src/authorization/setup.py
@@ -11,10 +11,10 @@
requires = [
    'pyramid',
    'pyramid_chameleon',
    'pyramid_debugtoolbar',
    'pyramid_tm',
    'pyramid_zodbconn',
    'transaction',
    'pyramid_tm',
    'pyramid_debugtoolbar',
    'ZODB3',
    'waitress',
    'docutils',
docs/tutorials/wiki/src/authorization/tutorial/templates/mytemplate.pt
@@ -1,73 +1,66 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" xmlns:tal="http://xml.zope.org/namespaces/tal">
<head>
  <title>The Pyramid Web Framework</title>
  <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
  <meta name="keywords" content="python web application" />
  <meta name="description" content="pyramid web application" />
  <link rel="shortcut icon" href="/static/favicon.ico" />
  <link rel="stylesheet" href="/static/pylons.css" type="text/css" media="screen" charset="utf-8" />
  <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen" />
  <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen" />
  <!--[if lte IE 6]>
  <link rel="stylesheet" href="/static/ie6.css" type="text/css" media="screen" charset="utf-8" />
  <![endif]-->
</head>
<body>
  <div id="wrap">
    <div id="top">
      <div class="top align-center">
        <div><img src="/static/pyramid.png" width="750" height="169" alt="pyramid"/></div>
      </div>
    </div>
    <div id="middle">
      <div class="middle align-center">
        <p class="app-welcome">
          Welcome to <span class="app-name">${project}</span>, an application generated by<br/>
          the Pyramid Web Framework.
        </p>
      </div>
    </div>
    <div id="bottom">
      <div class="bottom">
        <div id="left" class="align-right">
          <h2>Search documentation</h2>
          <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/current/search.html">
                <input type="text" id="q" name="q" value="" />
                <input type="submit" id="x" value="Go" />
            </form>
<!DOCTYPE html>
<html lang="${request.locale_name}">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="pyramid web application">
    <meta name="author" content="Pylons Project">
    <link rel="shortcut icon" href="${request.static_url('tutorial:static/pyramid-16x16.png')}">
    <title>ZODB Scaffold for The Pyramid Web Framework</title>
    <!-- Bootstrap core CSS -->
    <link href="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
    <!-- Custom styles for this scaffold -->
    <link href="${request.static_url('tutorial:static/theme.css')}" rel="stylesheet">
    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
    <![endif]-->
  </head>
  <body>
    <div class="starter-template">
      <div class="container">
        <div class="row">
          <div class="col-md-2">
            <img class="logo img-responsive" src="${request.static_url('tutorial:static/pyramid.png')}" alt="pyramid web framework">
          </div>
          <div class="col-md-10">
            <div class="content">
              <h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">ZODB scaffold</span></h1>
              <p class="lead">Welcome to <span class="font-normal">${project}</span>, an&nbsp;application generated&nbsp;by<br>the <span class="font-normal">Pyramid Web Framework</span>.</p>
            </div>
          </div>
        </div>
        <div id="right" class="align-left">
          <h2>Pyramid links</h2>
          <ul class="links">
            <li>
              <a href="http://pylonsproject.org/">Pylons Website</a>
            </li>
            <li>
              <a href="http://docs.pylonsproject.org/projects/pyramid/current/#narrative-documentation">Narrative Documentation</a>
            </li>
            <li>
              <a href="http://docs.pylonsproject.org/projects/pyramid/current/#api-documentation">API Documentation</a>
            </li>
            <li>
              <a href="http://docs.pylonsproject.org/projects/pyramid/current/#tutorials">Tutorials</a>
            </li>
            <li>
              <a href="http://docs.pylonsproject.org/projects/pyramid/current/#change-history">Change History</a>
            </li>
            <li>
              <a href="http://docs.pylonsproject.org/projects/pyramid/current/#sample-applications">Sample Applications</a>
            </li>
            <li>
              <a href="http://docs.pylonsproject.org/projects/pyramid/current/#support-and-development">Support and Development</a>
            </li>
            <li>
              <a href="irc://irc.freenode.net#pyramid">IRC Channel</a>
            </li>
        <div class="row">
          <div class="links">
            <ul>
              <li><i class="glyphicon glyphicon-bookmark icon-muted"></i><a href="http://docs.pylonsproject.org/projects/pyramid/en/latest/">Docs</a></li>
              <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li>
              <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="irc://irc.freenode.net#pyramid">IRC Channel</a></li>
              <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="http://pylonsproject.org">Pylons Project</a></li>
            </ul>
          </div>
        </div>
        <div class="row">
          <div class="copyright">
            Copyright &copy; Pylons Project
          </div>
        </div>
      </div>
    </div>
  </div>
</body>
    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script>
  </body>
</html>
docs/tutorials/wiki/src/basiclayout/setup.py
@@ -11,10 +11,10 @@
requires = [
    'pyramid',
    'pyramid_chameleon',
    'pyramid_debugtoolbar',
    'pyramid_tm',
    'pyramid_zodbconn',
    'transaction',
    'pyramid_tm',
    'pyramid_debugtoolbar',
    'ZODB3',
    'waitress',
    ]
docs/tutorials/wiki/src/basiclayout/tutorial/templates/mytemplate.pt
@@ -8,7 +8,7 @@
    <meta name="author" content="Pylons Project">
    <link rel="shortcut icon" href="${request.static_url('tutorial:static/pyramid-16x16.png')}">
    <title>Alchemy Scaffold for The Pyramid Web Framework</title>
    <title>ZODB Scaffold for The Pyramid Web Framework</title>
    <!-- Bootstrap core CSS -->
    <link href="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
docs/tutorials/wiki/src/models/setup.py
@@ -11,10 +11,10 @@
requires = [
    'pyramid',
    'pyramid_chameleon',
    'pyramid_debugtoolbar',
    'pyramid_tm',
    'pyramid_zodbconn',
    'transaction',
    'pyramid_tm',
    'pyramid_debugtoolbar',
    'ZODB3',
    'waitress',
    ]
docs/tutorials/wiki/src/models/tutorial/templates/mytemplate.pt
@@ -8,7 +8,7 @@
    <meta name="author" content="Pylons Project">
    <link rel="shortcut icon" href="${request.static_url('tutorial:static/pyramid-16x16.png')}">
    <title>Alchemy Scaffold for The Pyramid Web Framework</title>
    <title>ZODB Scaffold for The Pyramid Web Framework</title>
    <!-- Bootstrap core CSS -->
    <link href="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
docs/tutorials/wiki/src/tests/setup.py
@@ -11,10 +11,10 @@
requires = [
    'pyramid',
    'pyramid_chameleon',
    'pyramid_debugtoolbar',
    'pyramid_tm',
    'pyramid_zodbconn',
    'transaction',
    'pyramid_tm',
    'pyramid_debugtoolbar',
    'ZODB3',
    'waitress',
    'docutils',
docs/tutorials/wiki/src/tests/tutorial/templates/mytemplate.pt
@@ -1,73 +1,66 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" xmlns:tal="http://xml.zope.org/namespaces/tal">
<head>
  <title>The Pyramid Web Framework</title>
  <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
  <meta name="keywords" content="python web application" />
  <meta name="description" content="pyramid web application" />
  <link rel="shortcut icon" href="/static/favicon.ico" />
  <link rel="stylesheet" href="/static/pylons.css" type="text/css" media="screen" charset="utf-8" />
  <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen" />
  <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen" />
  <!--[if lte IE 6]>
  <link rel="stylesheet" href="/static/ie6.css" type="text/css" media="screen" charset="utf-8" />
  <![endif]-->
</head>
<body>
  <div id="wrap">
    <div id="top">
      <div class="top align-center">
        <div><img src="/static/pyramid.png" width="750" height="169" alt="pyramid"/></div>
      </div>
    </div>
    <div id="middle">
      <div class="middle align-center">
        <p class="app-welcome">
          Welcome to <span class="app-name">${project}</span>, an application generated by<br/>
          the Pyramid Web Framework.
        </p>
      </div>
    </div>
    <div id="bottom">
      <div class="bottom">
        <div id="left" class="align-right">
          <h2>Search documentation</h2>
          <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/current/search.html">
                <input type="text" id="q" name="q" value="" />
                <input type="submit" id="x" value="Go" />
            </form>
<!DOCTYPE html>
<html lang="${request.locale_name}">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="pyramid web application">
    <meta name="author" content="Pylons Project">
    <link rel="shortcut icon" href="${request.static_url('tutorial:static/pyramid-16x16.png')}">
    <title>ZODB Scaffold for The Pyramid Web Framework</title>
    <!-- Bootstrap core CSS -->
    <link href="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
    <!-- Custom styles for this scaffold -->
    <link href="${request.static_url('tutorial:static/theme.css')}" rel="stylesheet">
    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
    <![endif]-->
  </head>
  <body>
    <div class="starter-template">
      <div class="container">
        <div class="row">
          <div class="col-md-2">
            <img class="logo img-responsive" src="${request.static_url('tutorial:static/pyramid.png')}" alt="pyramid web framework">
          </div>
          <div class="col-md-10">
            <div class="content">
              <h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">ZODB scaffold</span></h1>
              <p class="lead">Welcome to <span class="font-normal">${project}</span>, an&nbsp;application generated&nbsp;by<br>the <span class="font-normal">Pyramid Web Framework</span>.</p>
            </div>
          </div>
        </div>
        <div id="right" class="align-left">
          <h2>Pyramid links</h2>
          <ul class="links">
            <li>
              <a href="http://pylonsproject.org/">Pylons Website</a>
            </li>
            <li>
              <a href="http://docs.pylonsproject.org/projects/pyramid/current/#narrative-documentation">Narrative Documentation</a>
            </li>
            <li>
              <a href="http://docs.pylonsproject.org/projects/pyramid/current/#api-documentation">API Documentation</a>
            </li>
            <li>
              <a href="http://docs.pylonsproject.org/projects/pyramid/current/#tutorials">Tutorials</a>
            </li>
            <li>
              <a href="http://docs.pylonsproject.org/projects/pyramid/current/#change-history">Change History</a>
            </li>
            <li>
              <a href="http://docs.pylonsproject.org/projects/pyramid/current/#sample-applications">Sample Applications</a>
            </li>
            <li>
              <a href="http://docs.pylonsproject.org/projects/pyramid/current/#support-and-development">Support and Development</a>
            </li>
            <li>
              <a href="irc://irc.freenode.net#pyramid">IRC Channel</a>
            </li>
        <div class="row">
          <div class="links">
            <ul>
              <li><i class="glyphicon glyphicon-bookmark icon-muted"></i><a href="http://docs.pylonsproject.org/projects/pyramid/en/latest/">Docs</a></li>
              <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li>
              <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="irc://irc.freenode.net#pyramid">IRC Channel</a></li>
              <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="http://pylonsproject.org">Pylons Project</a></li>
            </ul>
          </div>
        </div>
        <div class="row">
          <div class="copyright">
            Copyright &copy; Pylons Project
          </div>
        </div>
      </div>
    </div>
  </div>
</body>
    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script>
  </body>
</html>
docs/tutorials/wiki/src/views/setup.py
@@ -11,10 +11,10 @@
requires = [
    'pyramid',
    'pyramid_chameleon',
    'pyramid_debugtoolbar',
    'pyramid_tm',
    'pyramid_zodbconn',
    'transaction',
    'pyramid_tm',
    'pyramid_debugtoolbar',
    'ZODB3',
    'waitress',
    'docutils',
docs/tutorials/wiki/src/views/tutorial/static/favicon.ico
Binary files differ
docs/tutorials/wiki/src/views/tutorial/static/footerbg.png
Binary files differ
docs/tutorials/wiki/src/views/tutorial/static/headerbg.png
Binary files differ
docs/tutorials/wiki/src/views/tutorial/static/ie6.css
File was deleted
docs/tutorials/wiki/src/views/tutorial/static/middlebg.png
Binary files differ
docs/tutorials/wiki/src/views/tutorial/static/pylons.css
File was deleted
docs/tutorials/wiki/src/views/tutorial/static/pyramid-16x16.png
docs/tutorials/wiki/src/views/tutorial/static/pyramid-small.png
Binary files differ
docs/tutorials/wiki/src/views/tutorial/static/pyramid.png

docs/tutorials/wiki/src/views/tutorial/static/theme.css
New file
@@ -0,0 +1,154 @@
@import url(//fonts.googleapis.com/css?family=Open+Sans:300,400,600,700);
body {
  font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-weight: 300;
  color: #ffffff;
  background: #bc2131;
}
h1,
h2,
h3,
h4,
h5,
h6 {
  font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-weight: 300;
}
p {
  font-weight: 300;
}
.font-normal {
  font-weight: 400;
}
.font-semi-bold {
  font-weight: 600;
}
.font-bold {
  font-weight: 700;
}
.starter-template {
  margin-top: 250px;
}
.starter-template .content {
  margin-left: 10px;
}
.starter-template .content h1 {
  margin-top: 10px;
  font-size: 60px;
}
.starter-template .content h1 .smaller {
  font-size: 40px;
  color: #f2b7bd;
}
.starter-template .content .lead {
  font-size: 25px;
  color: #f2b7bd;
}
.starter-template .content .lead .font-normal {
  color: #ffffff;
}
.starter-template .links {
  float: right;
  right: 0;
  margin-top: 125px;
}
.starter-template .links ul {
  display: block;
  padding: 0;
  margin: 0;
}
.starter-template .links ul li {
  list-style: none;
  display: inline;
  margin: 0 10px;
}
.starter-template .links ul li:first-child {
  margin-left: 0;
}
.starter-template .links ul li:last-child {
  margin-right: 0;
}
.starter-template .links ul li.current-version {
  color: #f2b7bd;
  font-weight: 400;
}
.starter-template .links ul li a, a {
  color: #f2b7bd;
  text-decoration: underline;
}
.starter-template .links ul li a:hover, a:hover {
  color: #ffffff;
  text-decoration: underline;
}
.starter-template .links ul li .icon-muted {
  color: #eb8b95;
  margin-right: 5px;
}
.starter-template .links ul li:hover .icon-muted {
  color: #ffffff;
}
.starter-template .copyright {
  margin-top: 10px;
  font-size: 0.9em;
  color: #f2b7bd;
  text-transform: lowercase;
  float: right;
  right: 0;
}
@media (max-width: 1199px) {
  .starter-template .content h1 {
    font-size: 45px;
  }
  .starter-template .content h1 .smaller {
    font-size: 30px;
  }
  .starter-template .content .lead {
    font-size: 20px;
  }
}
@media (max-width: 991px) {
  .starter-template {
    margin-top: 0;
  }
  .starter-template .logo {
    margin: 40px auto;
  }
  .starter-template .content {
    margin-left: 0;
    text-align: center;
  }
  .starter-template .content h1 {
    margin-bottom: 20px;
  }
  .starter-template .links {
    float: none;
    text-align: center;
    margin-top: 60px;
  }
  .starter-template .copyright {
    float: none;
    text-align: center;
  }
}
@media (max-width: 767px) {
  .starter-template .content h1 .smaller {
    font-size: 25px;
    display: block;
  }
  .starter-template .content .lead {
    font-size: 16px;
  }
  .starter-template .links {
    margin-top: 40px;
  }
  .starter-template .links ul li {
    display: block;
    margin: 0;
  }
  .starter-template .links ul li .icon-muted {
    display: none;
  }
  .starter-template .copyright {
    margin-top: 20px;
  }
}
docs/tutorials/wiki/src/views/tutorial/static/theme.min.css
New file
@@ -0,0 +1 @@
@import url(//fonts.googleapis.com/css?family=Open+Sans:300,400,600,700);body{font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:300;color:#fff;background:#bc2131}h1,h2,h3,h4,h5,h6{font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:300}p{font-weight:300}.font-normal{font-weight:400}.font-semi-bold{font-weight:600}.font-bold{font-weight:700}.starter-template{margin-top:250px}.starter-template .content{margin-left:10px}.starter-template .content h1{margin-top:10px;font-size:60px}.starter-template .content h1 .smaller{font-size:40px;color:#f2b7bd}.starter-template .content .lead{font-size:25px;color:#f2b7bd}.starter-template .content .lead .font-normal{color:#fff}.starter-template .links{float:right;right:0;margin-top:125px}.starter-template .links ul{display:block;padding:0;margin:0}.starter-template .links ul li{list-style:none;display:inline;margin:0 10px}.starter-template .links ul li:first-child{margin-left:0}.starter-template .links ul li:last-child{margin-right:0}.starter-template .links ul li.current-version{color:#f2b7bd;font-weight:400}.starter-template .links ul li a{color:#fff}.starter-template .links ul li a:hover{text-decoration:underline}.starter-template .links ul li .icon-muted{color:#eb8b95;margin-right:5px}.starter-template .links ul li:hover .icon-muted{color:#fff}.starter-template .copyright{margin-top:10px;font-size:.9em;color:#f2b7bd;text-transform:lowercase;float:right;right:0}@media (max-width:1199px){.starter-template .content h1{font-size:45px}.starter-template .content h1 .smaller{font-size:30px}.starter-template .content .lead{font-size:20px}}@media (max-width:991px){.starter-template{margin-top:0}.starter-template .logo{margin:40px auto}.starter-template .content{margin-left:0;text-align:center}.starter-template .content h1{margin-bottom:20px}.starter-template .links{float:none;text-align:center;margin-top:60px}.starter-template .copyright{float:none;text-align:center}}@media (max-width:767px){.starter-template .content h1 .smaller{font-size:25px;display:block}.starter-template .content .lead{font-size:16px}.starter-template .links{margin-top:40px}.starter-template .links ul li{display:block;margin:0}.starter-template .links ul li .icon-muted{display:none}.starter-template .copyright{margin-top:20px}}
docs/tutorials/wiki/src/views/tutorial/static/transparent.gif
Binary files differ
docs/tutorials/wiki/src/views/tutorial/templates/edit.pt
@@ -1,58 +1,69 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
      xmlns:tal="http://xml.zope.org/namespaces/tal">
<head>
  <title>${page.__name__} - Pyramid tutorial wiki (based on
<!DOCTYPE html>
<html lang="${request.locale_name}">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="pyramid web application">
    <meta name="author" content="Pylons Project">
    <link rel="shortcut icon" href="${request.static_url('tutorial:static/pyramid-16x16.png')}">
    <title>${page.__name__} - Pyramid tutorial wiki (based on
    TurboGears 20-Minute Wiki)</title>
  <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
  <meta name="keywords" content="python web application" />
  <meta name="description" content="pyramid web application" />
  <link rel="shortcut icon"
        href="/static/favicon.ico" />
  <link rel="stylesheet"
        href="/static/pylons.css"
        type="text/css" media="screen" charset="utf-8" />
  <!--[if lte IE 6]>
  <link rel="stylesheet"
        href="/static/ie6.css"
        type="text/css" media="screen" charset="utf-8" />
  <![endif]-->
</head>
<body>
  <div id="wrap">
    <div id="top-small">
      <div class="top-small align-center">
        <div>
          <img width="220" height="50" alt="pyramid"
        src="/static/pyramid-small.png" />
    <!-- Bootstrap core CSS -->
    <link href="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
    <!-- Custom styles for this scaffold -->
    <link href="${request.static_url('tutorial:static/theme.css')}" rel="stylesheet">
    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
    <![endif]-->
  </head>
  <body>
    <div class="starter-template">
      <div class="container">
        <div class="row">
          <div class="col-md-2">
            <img class="logo img-responsive" src="${request.static_url('tutorial:static/pyramid.png')}" alt="pyramid web framework">
          </div>
          <div class="col-md-10">
            <div class="content">
              <p>
                  Editing <strong><span tal:replace="page.__name__">
                  Page Name Goes Here</span></strong>
              </p>
              <p>You can return to the
                <a href="${request.application_url}">FrontPage</a>.
              </p>
              <form action="${save_url}" method="post">
                <div class="form-group">
                  <textarea class="form-control" name="body" tal:content="page.data" rows="10" cols="60"></textarea>
                </div>
                <div class="form-group">
                  <button type="submit" name="form.submitted" value="Save" class="btn btn-default">Save</button>
                </div>
              </form>
            </div>
          </div>
        </div>
        <div class="row">
          <div class="copyright">
            Copyright &copy; Pylons Project
          </div>
        </div>
      </div>
    </div>
    <div id="middle">
      <div class="middle align-right">
        <div id="left" class="app-welcome align-left">
          Editing <b><span tal:replace="page.__name__">Page Name Goes
            Here</span></b><br/>
          You can return to the
          <a href="${request.application_url}">FrontPage</a>.<br/>
        </div>
        <div id="right" class="app-welcome align-right"></div>
      </div>
    </div>
    <div id="bottom">
      <div class="bottom">
        <form action="${save_url}" method="post">
          <textarea name="body" tal:content="page.data" rows="10"
                    cols="60"/><br/>
          <input type="submit" name="form.submitted" value="Save"/>
        </form>
      </div>
    </div>
  </div>
  <div id="footer">
    <div class="footer"
         >&copy; Copyright 2008-2011, Agendaless Consulting.</div>
  </div>
</body>
    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script>
  </body>
</html>
docs/tutorials/wiki/src/views/tutorial/templates/mytemplate.pt
@@ -1,76 +1,66 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" xmlns:tal="http://xml.zope.org/namespaces/tal">
<head>
  <title>The Pyramid Web Framework</title>
  <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
  <meta name="keywords" content="python web application" />
  <meta name="description" content="pyramid web application" />
  <link rel="shortcut icon" href="/static/favicon.ico" />
  <link rel="stylesheet" href="/static/pylons.css" type="text/css" media="screen" charset="utf-8" />
  <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen" />
  <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen" />
  <!--[if lte IE 6]>
  <link rel="stylesheet" href="/static/ie6.css" type="text/css" media="screen" charset="utf-8" />
  <![endif]-->
</head>
<body>
  <div id="wrap">
    <div id="top">
      <div class="top align-center">
        <div><img src="/static/pyramid.png" width="750" height="169" alt="pyramid"/></div>
      </div>
    </div>
    <div id="middle">
      <div class="middle align-center">
        <p class="app-welcome">
          Welcome to <span class="app-name">${project}</span>, an application generated by<br/>
          the Pyramid Web Framework.
        </p>
      </div>
    </div>
    <div id="bottom">
      <div class="bottom">
        <div id="left" class="align-right">
          <h2>Search documentation</h2>
          <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/current/search.html">
                <input type="text" id="q" name="q" value="" />
                <input type="submit" id="x" value="Go" />
            </form>
<!DOCTYPE html>
<html lang="${request.locale_name}">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="pyramid web application">
    <meta name="author" content="Pylons Project">
    <link rel="shortcut icon" href="${request.static_url('tutorial:static/pyramid-16x16.png')}">
    <title>ZODB Scaffold for The Pyramid Web Framework</title>
    <!-- Bootstrap core CSS -->
    <link href="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
    <!-- Custom styles for this scaffold -->
    <link href="${request.static_url('tutorial:static/theme.css')}" rel="stylesheet">
    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
    <![endif]-->
  </head>
  <body>
    <div class="starter-template">
      <div class="container">
        <div class="row">
          <div class="col-md-2">
            <img class="logo img-responsive" src="${request.static_url('tutorial:static/pyramid.png')}" alt="pyramid web framework">
          </div>
          <div class="col-md-10">
            <div class="content">
              <h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">ZODB scaffold</span></h1>
              <p class="lead">Welcome to <span class="font-normal">${project}</span>, an&nbsp;application generated&nbsp;by<br>the <span class="font-normal">Pyramid Web Framework</span>.</p>
            </div>
          </div>
        </div>
        <div id="right" class="align-left">
          <h2>Pyramid links</h2>
          <ul class="links">
            <li>
              <a href="http://pylonsproject.org/">Pylons Website</a>
            </li>
            <li>
              <a href="http://docs.pylonsproject.org/projects/pyramid/current/#narrative-documentation">Narrative Documentation</a>
            </li>
            <li>
              <a href="http://docs.pylonsproject.org/projects/pyramid/current/#api-documentation">API Documentation</a>
            </li>
            <li>
              <a href="http://docs.pylonsproject.org/projects/pyramid/current/#tutorials">Tutorials</a>
            </li>
            <li>
              <a href="http://docs.pylonsproject.org/projects/pyramid/current/#change-history">Change History</a>
            </li>
            <li>
              <a href="http://docs.pylonsproject.org/projects/pyramid/current/#sample-applications">Sample Applications</a>
            </li>
            <li>
              <a href="http://docs.pylonsproject.org/projects/pyramid/current/#support-and-development">Support and Development</a>
            </li>
            <li>
              <a href="irc://irc.freenode.net#pyramid">IRC Channel</a>
            </li>
        <div class="row">
          <div class="links">
            <ul>
              <li><i class="glyphicon glyphicon-bookmark icon-muted"></i><a href="http://docs.pylonsproject.org/projects/pyramid/en/latest/">Docs</a></li>
              <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li>
              <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="irc://irc.freenode.net#pyramid">IRC Channel</a></li>
              <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="http://pylonsproject.org">Pylons Project</a></li>
            </ul>
          </div>
        </div>
        <div class="row">
          <div class="copyright">
            Copyright &copy; Pylons Project
          </div>
        </div>
      </div>
    </div>
  </div>
  <div id="footer">
    <div class="footer">&copy; Copyright 2008-2012, Agendaless Consulting.</div>
  </div>
</body>
    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script>
  </body>
</html>
docs/tutorials/wiki/src/views/tutorial/templates/view.pt
@@ -1,61 +1,69 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
      xmlns:tal="http://xml.zope.org/namespaces/tal">
<head>
  <title>${page.__name__} - Pyramid tutorial wiki (based on
      TurboGears 20-Minute Wiki)</title>
  <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
  <meta name="keywords" content="python web application" />
  <meta name="description" content="pyramid web application" />
  <link rel="shortcut icon"
        href="/static/favicon.ico" />
  <link rel="stylesheet"
        href="/static/pylons.css"
        type="text/css" media="screen" charset="utf-8" />
  <!--[if lte IE 6]>
  <link rel="stylesheet"
        href="/static/ie6.css"
        type="text/css" media="screen" charset="utf-8" />
  <![endif]-->
</head>
<body>
  <div id="wrap">
    <div id="top-small">
      <div class="top-small align-center">
        <div>
          <img width="220" height="50" alt="pyramid"
        src="/static/pyramid-small.png" />
<!DOCTYPE html>
<html lang="${request.locale_name}">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="pyramid web application">
    <meta name="author" content="Pylons Project">
    <link rel="shortcut icon" href="${request.static_url('tutorial:static/pyramid-16x16.png')}">
    <title>${page.name} - Pyramid tutorial wiki (based on
    TurboGears 20-Minute Wiki)</title>
    <!-- Bootstrap core CSS -->
    <link href="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
    <!-- Custom styles for this scaffold -->
    <link href="${request.static_url('tutorial:static/theme.css')}" rel="stylesheet">
    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
    <![endif]-->
  </head>
  <body>
    <div class="starter-template">
      <div class="container">
        <div class="row">
          <div class="col-md-2">
            <img class="logo img-responsive" src="${request.static_url('tutorial:static/pyramid.png')}" alt="pyramid web framework">
          </div>
          <div class="col-md-10">
            <div class="content">
              <div tal:replace="structure content">
                Page text goes here.
              </div>
              <p>
                <a tal:attributes="href edit_url" href="">
                  Edit this page
                </a>
              </p>
              <p>
                  Viewing <strong><span tal:replace="page.__name__">
                  Page Name Goes Here</span></strong>
              </p>
              <p>You can return to the
                <a href="${request.application_url}">FrontPage</a>.
              </p>
            </div>
          </div>
        </div>
        <div class="row">
          <div class="copyright">
            Copyright &copy; Pylons Project
          </div>
        </div>
      </div>
    </div>
    <div id="middle">
      <div class="middle align-right">
        <div id="left" class="app-welcome align-left">
          Viewing <b><span tal:replace="page.__name__">Page Name Goes
          Here</span></b><br/>
          You can return to the
          <a href="${request.application_url}">FrontPage</a>.<br/>
        </div>
        <div id="right" class="app-welcome align-right"></div>
      </div>
    </div>
    <div id="bottom">
      <div class="bottom">
        <div tal:replace="structure content">
          Page text goes here.
        </div>
        <p>
          <a tal:attributes="href edit_url" href="">
            Edit this page
          </a>
        </p>
      </div>
    </div>
  </div>
  <div id="footer">
    <div class="footer"
         >&copy; Copyright 2008-2011, Agendaless Consulting.</div>
  </div>
</body>
    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script>
  </body>
</html>
docs/tutorials/wiki2/definingviews.rst
@@ -23,26 +23,27 @@
about our custom application requirements.
We need to add a dependency on the ``docutils`` package to our ``tutorial``
package's ``setup.py`` file by assigning this dependency to the ``requires`` parameter in ``setup()``.
package's ``setup.py`` file by assigning this dependency to the ``requires``
parameter in the ``setup()`` function.
Open ``tutorial/setup.py`` and edit it to look like the following:
.. literalinclude:: src/views/setup.py
   :linenos:
   :language: python
   :emphasize-lines: 20
   :language: python
Only the highlighted line needs to be added.
Running ``setup.py develop``
============================
Since a new software dependency was added, you will need to rerun ``python
setup.py develop`` inside the root of the ``tutorial`` package to obtain and
register the newly added dependency distribution.
Since a new software dependency was added, you will need to run ``python
setup.py develop`` again inside the root of the ``tutorial`` package to obtain
and register the newly added dependency distribution.
Make sure your current working directory is the root of the project (the
directory in which setup.py lives) and execute the following command.
directory in which ``setup.py`` lives) and execute the following command.
On UNIX:
@@ -63,21 +64,24 @@
   Finished processing dependencies for tutorial==0.0
Changing the ``views.py`` File
==============================
Adding view functions in ``views.py``
=====================================
It's time for a major change.  Open ``tutorial/tutorial/views.py`` and edit it to look like the following:
It's time for a major change.  Open ``tutorial/tutorial/views.py`` and edit it
to look like the following:
.. literalinclude:: src/views/tutorial/views.py
   :linenos:
   :language: python
   :emphasize-lines: 1-7,14,16-72
The highlighted lines are the ones that need to be added or edited.
The highlighted lines need to be added or edited.
We got rid of the ``my_view`` view function and its decorator that was
added when we originally rendered the ``alchemy`` scaffold.  It was only an
example and isn't relevant to our application.
We added some imports and created a regular expression to find "WikiWords".
We got rid of the ``my_view`` view function and its decorator that was added
when we originally rendered the ``alchemy`` scaffold.  It was only an example
and isn't relevant to our application.
Then we added four :term:`view callable` functions to our ``views.py``
module: 
@@ -87,8 +91,7 @@
* ``add_page()`` - Allows the user to add a page.
* ``edit_page()`` - Allows the user to edit a page.
We'll describe each one briefly and show the resulting ``views.py`` file
afterward.
We'll describe each one briefly in the following sections.
.. note::
@@ -101,9 +104,7 @@
The ``view_wiki`` view function
-------------------------------
``view_wiki()`` is the :term:`default view` that gets called when a request
is made to the root URL of our wiki.  It always redirects to
a URL which represents the path to our "FrontPage".
Following is the code for the ``view_wiki`` view function and its decorator:
.. literalinclude:: src/views/tutorial/views.py
   :lines: 20-24
@@ -111,23 +112,23 @@
   :linenos:
   :language: python
``view_wiki()`` returns an instance of the
:class:`pyramid.httpexceptions.HTTPFound` class (instances of which implement
the :class:`pyramid.interfaces.IResponse` interface like
:class:`pyramid.response.Response` does).
``view_wiki()`` is the :term:`default view` that gets called when a request is
made to the root URL of our wiki.  It always redirects to an URL which
represents the path to our "FrontPage".
It uses the :meth:`pyramid.request.Request.route_url` API to construct a
URL to the ``FrontPage`` page (e.g., ``http://localhost:6543/FrontPage``), which
is used as the location of the ``HTTPFound`` response, forming an HTTP redirect.
The ``view_wiki`` view callable always redirects to the URL of a Page resource
named "FrontPage".  To do so, it returns an instance of the
:class:`pyramid.httpexceptions.HTTPFound` class (instances of which implement
the :class:`pyramid.interfaces.IResponse` interface, like
:class:`pyramid.response.Response` does). It uses the
:meth:`pyramid.request.Request.route_url` API to construct an URL to the
``FrontPage`` page (i.e., ``http://localhost:6543/FrontPage``), and uses it as
the "location" of the ``HTTPFound`` response, forming an HTTP redirect.
The ``view_page`` view function
-------------------------------
``view_page()`` is used to display a single page of our
wiki.  It renders the :term:`reStructuredText` body of a page (stored as
the ``data`` attribute of a ``Page`` model object) as HTML.  Then it substitutes an
HTML anchor for each *WikiWord* reference in the rendered HTML using a
compiled regular expression.
Here is the code for the ``view_page`` view function and its decorator:
.. literalinclude:: src/views/tutorial/views.py
   :lines: 25-45
@@ -135,7 +136,12 @@
   :linenos:
   :language: python
The ``check()`` function is used as the first argument to
``view_page()`` is used to display a single page of our wiki.  It renders the
:term:`reStructuredText` body of a page (stored as the ``data`` attribute of a
``Page`` model object) as HTML.  Then it substitutes an HTML anchor for each
*WikiWord* reference in the rendered HTML using a compiled regular expression.
The curried function named ``check`` is used as the first argument to
``wikiwords.sub``, indicating that it should be called to provide a value for
each WikiWord match found in the content.  If the wiki already contains a
page with the matched WikiWord name, ``check()`` generates a view
@@ -158,6 +164,14 @@
The ``add_page`` view function
------------------------------
Here is the code for the ``add_page`` view function and its decorator:
.. literalinclude:: src/views/tutorial/views.py
   :lines: 47-58
   :lineno-start: 47
   :linenos:
   :language: python
``add_page()`` is invoked when a user clicks on a *WikiWord* which
isn't yet represented as a page in the system.  The ``check`` function
within the ``view_page`` view generates URLs to this view.
@@ -165,12 +179,6 @@
when we want to add a page object.  The ``matchdict`` attribute of the
request passed to the ``add_page()`` view will have the values we need
to construct URLs and find model objects.
.. literalinclude:: src/views/tutorial/views.py
   :lines: 47-58
   :lineno-start: 47
   :linenos:
   :language: python
The ``matchdict`` will have a ``'pagename'`` key that matches the name of
the page we'd like to add.  If our add view is invoked via,
@@ -197,17 +205,19 @@
The ``edit_page`` view function
-------------------------------
``edit_page()`` is invoked when a user clicks the "Edit this
Page" button on the view form.  It renders an edit form but it also acts as
the handler for the form it renders.  The ``matchdict`` attribute of the
request passed to the ``edit_page`` view will have a ``'pagename'`` key
matching the name of the page the user wants to edit.
Here is the code for the ``edit_page`` view function and its decorator:
.. literalinclude:: src/views/tutorial/views.py
   :lines: 60-72
   :lineno-start: 60
   :linenos:
   :language: python
``edit_page()`` is invoked when a user clicks the "Edit this
Page" button on the view form.  It renders an edit form but it also acts as
the handler for the form it renders.  The ``matchdict`` attribute of the
request passed to the ``edit_page`` view will have a ``'pagename'`` key
matching the name of the page the user wants to edit.
If the view execution *is* a result of a form submission (i.e., the expression
``'form.submitted' in request.params`` is ``True``), the view grabs the
@@ -220,16 +230,16 @@
simply renders the edit form, passing the page object and a ``save_url``
which will be used as the action of the generated form.
Adding Templates
Adding templates
================
The ``view_page``, ``add_page`` and ``edit_page`` views that we've added
reference a :term:`template`.  Each template is a :term:`Chameleon` :term:`ZPT`
template.  These templates will live in the ``templates`` directory of our
tutorial package.  Chameleon templates must have a ``.pt`` extension to be
recognized as such.
reference a :term:`template`.  Each template is a :term:`Chameleon`
:term:`ZPT` template.  These templates will live in the ``templates``
directory of our tutorial package.  Chameleon templates must have a ``.pt``
extension to be recognized as such.
The ``view.pt`` Template
The ``view.pt`` template
------------------------
Create ``tutorial/tutorial/templates/view.pt`` and add the following
@@ -242,15 +252,13 @@
This template is used by ``view_page()`` for displaying a single
wiki page. It includes:
- A ``div`` element that is replaced with the ``content``
  value provided by the view (lines 36-38).  ``content``
  contains HTML, so the ``structure`` keyword is used
  to prevent escaping it (i.e., changing ">" to "&gt;", etc.)
- A link that points
  at the "edit" URL which invokes the ``edit_page`` view for
  the page being viewed (lines 40-42).
- A ``div`` element that is replaced with the ``content`` value provided by
  the view (lines 36-38).  ``content`` contains HTML, so the ``structure``
  keyword is used to prevent escaping it (i.e., changing ">" to "&gt;", etc.)
- A link that points at the "edit" URL which invokes the ``edit_page`` view
  for the page being viewed (lines 40-42).
The ``edit.pt`` Template
The ``edit.pt`` template
------------------------
Create ``tutorial/tutorial/templates/edit.pt`` and add the following
@@ -260,24 +268,21 @@
   :linenos:
   :language: html
This template is used by ``add_page()`` and ``edit_page()`` for adding
and editing a wiki page.  It displays a page containing a form that includes:
This template is used by ``add_page()`` and ``edit_page()`` for adding and
editing a wiki page.  It displays a page containing a form that includes:
- A 10 row by 60 column ``textarea`` field named ``body`` that is filled
  with any existing page data when it is rendered (line 45).
- A submit button that has the name ``form.submitted`` (line 48).
The form POSTs back to the ``save_url`` argument supplied
by the view (line 43).  The view will use the ``body`` and
``form.submitted`` values.
The form POSTs back to the ``save_url`` argument supplied by the view (line
43).  The view will use the ``body`` and ``form.submitted`` values.
.. note:: Our templates use a ``request`` object that
   none of our tutorial views return in their dictionary.
   ``request`` is one of several
   names that are available "by default" in a template when a template
   renderer is used.  See :ref:`renderer_system_values` for
   information about other names that are available by default
   when a template is used as a renderer.
.. note:: Our templates use a ``request`` object that none of our tutorial
   views return in their dictionary. ``request`` is one of several names that
   are available "by default" in a template when a template renderer is used.
   See :ref:`renderer_system_values` for information about other names that
   are available by default when a template is used as a renderer.
Static Assets
-------------
@@ -347,21 +352,19 @@
:ref:`wiki2-start-the-application`).  Launch a browser and visit
each of the following URLs, checking that the result is as expected:
- http://localhost:6543 in a browser invokes the
  ``view_wiki`` view.  This always redirects to the ``view_page`` view
  of the FrontPage page object.
- ``http://localhost:6543/`` invokes the ``view_wiki`` view.  This always
  redirects to the ``view_page`` view of the ``FrontPage`` page object.
- http://localhost:6543/FrontPage in a browser invokes
  the ``view_page`` view of the front page object.
- http://localhost:6543/FrontPage invokes the ``view_page`` view of the front
  page object.
- http://localhost:6543/FrontPage/edit_page in a browser
  invokes the edit view for the front page object.
- http://localhost:6543/FrontPage/edit_page invokes the edit view for the
  front page object.
- http://localhost:6543/add_page/SomePageName in a
  browser invokes the add view for a page.
- http://localhost:6543/add_page/SomePageName invokes the add view for a page.
- To generate an error, visit http://localhost:6543/foobars/edit_page which
  will generate a ``NoResultFound: No row was found for one()`` error.
  You'll see an interactive traceback facility provided
  by :term:`pyramid_debugtoolbar`.
  will generate a ``NoResultFound: No row was found for one()`` error. You'll
  see an interactive traceback facility provided by
  :term:`pyramid_debugtoolbar`.