diff --git a/CHANGELOG.md b/CHANGELOG.md index 55ce5e8..0935339 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ All notable changes to wuttaweb will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## v0.11.0 (2024-08-20) + +### Feat + +- split up base templates into more sections (def blocks) +- simplify base/page/form template structure; add docs + ## v0.10.2 (2024-08-19) ### Fix diff --git a/docs/narr/index.rst b/docs/narr/index.rst index 20f3a85..f9beea1 100644 --- a/docs/narr/index.rst +++ b/docs/narr/index.rst @@ -2,15 +2,7 @@ Documentation ============= -TODO +.. toctree:: + :maxdepth: 2 -.. - .. toctree:: - :maxdepth: 2 - - install/index - config/index - cli/index - handlers/index - providers/index - db/index + templates/index diff --git a/docs/narr/templates/base.rst b/docs/narr/templates/base.rst new file mode 100644 index 0000000..554c721 --- /dev/null +++ b/docs/narr/templates/base.rst @@ -0,0 +1,251 @@ + +Base Templates +============== + +This describes the base templates. When creating a custom page +template, you most often need to inherit from one of these: + +* :ref:`page_base_template` +* :ref:`form_base_template` +* :ref:`master_base_templates` + +.. note:: + + Any of these templates may be overridden; see + :ref:`mako-template-override`. + + +Global Base +~~~~~~~~~~~ + +There is exactly one "true base template" for the web app, designated +as: ``/base.mako`` + +The default base template is ``wuttaweb:templates/base.mako`` and all +page templates inherit from it. However they inherit it by *name* +only (``/base.mako``) - therefore if you override this via custom +template search paths, effectively you have changed the **theme**. + +In addition to general layout/structure, this template is reponsible +for creating the Vue app which encompasses the whole of every page. +It also establishes the ``WholePage`` component which is the Vue app's +one and only child component. + +(``WholePage`` in turn will have other children, for page content.) + +There is usually no need to define a template which inherits directly +from ``/base.mako``, rather you should inherit from ``/page.mako`` +(see next section) or similar. + +As pertains to Vue component logic, there are 3 blocks which you may +find a need to override. These are defined by ``/base.mako`` so will +apply to *all* templates: + +* ``render_vue_templates()`` +* ``modify_vue_vars()`` +* ``make_vue_components()`` + +Most often it is necessary to customize ``modify_vue_vars()`` but keep +reading for an example. + + +.. _page_base_template: + +Page Base +~~~~~~~~~ + +The common base template for pages, designated as: ``/page.mako`` + +This extends the Vue logic from ``/base.mako`` by establishing +``ThisPage`` component, which wraps all content within the current +page. + +The final structure then is conceptually like: + +.. code-block:: html + + <div id="app"> + <whole-page> + <!-- menu etc. --> + <this-page> + <!-- page contents --> + </this-page> + </whole-page> + </div> + +Simple usage is to create a template which inherits from +``/page.mako`` and defines a ``page_content()`` block, e.g.: + +.. code-block:: mako + + <%inherit file="/page.mako" /> + + <%def name="page_content()"> + <p>hello world!</p> + </%def> + +The default ``/page.mako`` logic knows where to render the +``page_content()`` block so that it fits properly into the +component/layout structure. + +Often you may need to customize Vue component logic for a page; this +is done by defining one of the blocks mentioned in previous section. + +Here is a simple example which shows how this works: + +.. code-block:: mako + + <%inherit file="/page.mako" /> + + <%def name="page_content()"> + <b-field label="Foo"> + <b-input v-model="foo" /> + </b-field> + <b-field> + <b-button @click="alertFoo()"> + Alert + </b-button> + </b-field> + </%def> + + <%def name="modify_vue_vars()"> + ${parent.modify_vue_vars()} + <script> + + // nb. this becomes ThisPage.data.foo + ThisPageData.foo = 'bar' + + ThisPage.methods.alertFoo = function() { + alert("value of foo is: " + this.foo) + } + + </script> + </%def> + +You can see that ``page_content()`` is able to reference things from +``ThisPage`` component, while the ``modify_vue_vars()`` block is used +to define those same things on the component. + + +.. _form_base_template: + +Form Base +~~~~~~~~~ + +The common base template for pages with a form, designated as: +``/form.mako`` + +This expects the context dict to contain ``'form'`` which points to a +:class:`~wuttaweb.forms.base.Form` instance. + +This template extends the Vue logic from ``/page.mako`` by +establishing a Vue component specific to the form object. + +The final structure then is conceptually like: + +.. code-block:: html + + <div id="app"> + <whole-page> + <!-- menu etc. --> + <this-page> + <wutta-form> + <!-- fields etc. --> + </wutta-form> + </this-page> + </whole-page> + </div> + +A simple example which assumes one of the form fields exposes a button +with click event that triggers ``alertFoo()`` method on the form +component: + +.. code-block:: mako + + <%inherit file="/form.mako" /> + + <%def name="modify_vue_vars()"> + ${parent.modify_vue_vars()} + <script> + + // nb. this becomes e.g. WuttaForm.foo when component is created + ${form.vue_component}Data.foo = 'bar' + + ${form.vue_component}.methods.alertFoo = function() { + alert("value of foo is: " + this.foo) + } + + </script> + </%def> + +.. note:: + + By default, ``${form.vue_compoment}`` is rendered as ``WuttaForm`` + but that is not guaranteed. You should resist the temptation to + hard-code that; always use ``${form.vue_component}`` and (where + applicable) ``${form.vue_tagname}``. + + The reason for this is to allow multiple forms to exist on a single + page, each with a separate Vue component. (Which is not shown in + the above example.) + + See also :attr:`~wuttaweb.forms.base.Form.vue_component` and + :attr:`~wuttaweb.forms.base.Form.vue_tagname`. + + +.. _master_base_templates: + +Master Base +~~~~~~~~~~~ + +These templates are for use with +:class:`~wuttaweb.views.master.MasterView`. Each is the default +template used for the corresponding route/view, unless a more specific +template is defined. + +The "index" template is unique in that it is (usually) for listing the +model data: + +* ``/master/index.mako`` + +The "form" template is just a base template, does not directly +correspond to a route/view. Other CRUD templates inherit from it. +This inherits from ``/form.mako`` (see previous section). + +* ``/master/form.mako`` + +These CRUD templates inherit from ``/master/form.mako`` and so +require a ``'form'`` in the context dict. + +* ``/master/create.mako`` +* ``/master/view.mako`` +* ``/master/edit.mako`` +* ``/master/delete.mako`` + +The "configure" template is for master views which have a +configuration page. + +* ``/master/configure.mako`` + +Usage for these is not significantly different from the ones shown +above, in cases where you actually need to override the template. + +As an example let's say you have defined a ``WidgetMasterView`` class +and want to override its "view" template. You would then create a +file as ``/widgets/view.mako`` (within your templates folder) and +be sure to inherit from the correct base template: + +.. code-block:: mako + + <%inherit file="/master/view.mako" /> + + <%def name="page_content()"> + + <p>THIS APPEARS FIRST!</p> + + ## nb. the form will appear here + ${parent.page_content()} + + <p>MADE IT TO THE END!</p> + + </%def> diff --git a/docs/narr/templates/index.rst b/docs/narr/templates/index.rst new file mode 100644 index 0000000..d560666 --- /dev/null +++ b/docs/narr/templates/index.rst @@ -0,0 +1,10 @@ + +Templates +========= + +.. toctree:: + :maxdepth: 2 + + overview + base + lookup diff --git a/docs/narr/templates/lookup.rst b/docs/narr/templates/lookup.rst new file mode 100644 index 0000000..11247c2 --- /dev/null +++ b/docs/narr/templates/lookup.rst @@ -0,0 +1,69 @@ + +Template Lookup +=============== + +The discovery of templates is handled by Mako, and is configurable. + +WuttaWeb comes with all templates it needs, in the path designated as +``wuttaweb:templates``. + +When the app renders a page, it invokes the Mako lookup logic, which +searches one or more folders and returns the first matching file it +encounters. By default ``wuttaweb:templates`` is the only place it +looks. + +A template is searched for by "name" but it is more path-like, e.g. +``/page.mako`` or ``/master/index.mako`` etc. So for example the file +at ``wuttaweb:templates/home.mako`` is used for home page (using +lookup name ``/home.mako``) by default. + + +.. _mako-template-override: + +Overriding the Search Paths +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The basic idea is to give it a list of paths it should search when +trying to find a template. The first template file found for a given +search name is used and no further search is done for that name. + +You can define the Mako lookup sequence in your ``web.conf`` as +follows: + +.. code-block:: ini + + [app:main] + mako.directories = + /random/path/on/disk + poser.web:templates + wuttaweb:templates + +This setting is interpreted by ``pyramid_mako`` (`docs`_). + +.. _docs: https://docs.pylonsproject.org/projects/pyramid_mako/en/latest/index.html#mako-directories + +Here ``wuttaweb:templates/home.mako`` would still be used by default +for home page, *unless* e.g. ``/random/path/on/disk/home.mako`` +existed in which case that would be used. + +Each path can have an arbitrary set of templates, they will +effectively be combined to a single set by the app, with the +definition order determining search priority. + +If you are already using a custom ``app.main()`` function for +constructing the web app during startup, it may be a good idea to +change the *default* search paths to include your package. + +Setup for custom ``app.main()`` is beyond the scope here, but assuming +you *do* already have one, this is what it looks like:: + + from wuttaweb import app as base + + def main(global_config, **settings): + + # nb. set the *default* mako search paths; however config can + # still override with method shown above + settings.setdefault('mako.directories', ['poser.web:templates', + 'wuttaweb:templates']) + + return base.main(global_config, **settings) diff --git a/docs/narr/templates/overview.rst b/docs/narr/templates/overview.rst new file mode 100644 index 0000000..4801e17 --- /dev/null +++ b/docs/narr/templates/overview.rst @@ -0,0 +1,15 @@ + +Overview +======== + +WuttaWeb uses the `Mako`_ template language for page rendering. + +.. _Mako: https://www.makotemplates.org/ + +There is a "global" base template which effectively defines the +"theme" (page layout, Vue component structure). A few other base +templates provide a starting point for any custom pages; see +:doc:`base`. + +Templates are found via lookup which is handled by Mako. This is +configurable so you can override any or all; see :doc:`lookup`. diff --git a/pyproject.toml b/pyproject.toml index 5902f86..fe91ac9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "hatchling.build" [project] name = "WuttaWeb" -version = "0.10.2" +version = "0.11.0" description = "Web App for Wutta Framework" readme = "README.md" authors = [{name = "Lance Edgar", email = "lance@edbob.org"}] diff --git a/src/wuttaweb/templates/appinfo/configure.mako b/src/wuttaweb/templates/appinfo/configure.mako index 1ea6481..da7d94d 100644 --- a/src/wuttaweb/templates/appinfo/configure.mako +++ b/src/wuttaweb/templates/appinfo/configure.mako @@ -140,8 +140,8 @@ </div> </%def> -<%def name="modify_this_page_vars()"> - ${parent.modify_this_page_vars()} +<%def name="modify_vue_vars()"> + ${parent.modify_vue_vars()} <script> ThisPageData.weblibs = ${json.dumps(weblibs or [])|n} diff --git a/src/wuttaweb/templates/appinfo/index.mako b/src/wuttaweb/templates/appinfo/index.mako index 710d02c..342617e 100644 --- a/src/wuttaweb/templates/appinfo/index.mako +++ b/src/wuttaweb/templates/appinfo/index.mako @@ -48,8 +48,8 @@ </%def> -<%def name="modify_this_page_vars()"> - ${parent.modify_this_page_vars()} +<%def name="modify_vue_vars()"> + ${parent.modify_vue_vars()} <script> ThisPageData.configFiles = ${json.dumps([dict(path=p, priority=i) for i, p in enumerate(config.get_prioritized_files(), 1)])|n} </script> diff --git a/src/wuttaweb/templates/auth/login.mako b/src/wuttaweb/templates/auth/login.mako index 6f07542..e6b77c6 100644 --- a/src/wuttaweb/templates/auth/login.mako +++ b/src/wuttaweb/templates/auth/login.mako @@ -19,7 +19,8 @@ </div> </%def> -<%def name="modify_this_page_vars()"> +<%def name="modify_vue_vars()"> + ${parent.modify_vue_vars()} <script> ${form.vue_component}Data.usernameInput = null diff --git a/src/wuttaweb/templates/base.mako b/src/wuttaweb/templates/base.mako index 32635d7..ddee561 100644 --- a/src/wuttaweb/templates/base.mako +++ b/src/wuttaweb/templates/base.mako @@ -15,17 +15,27 @@ <whole-page /> </div> + ## nb. sometimes a template needs to define something + ## before the body content proper is rendered + ${self.before_content()} + ## content body from derived/child template ${self.body()} ## Vue app - ${self.make_whole_page_component()} - ${self.make_whole_page_app()} + ${self.render_vue_templates()} + ${self.modify_vue_vars()} + ${self.make_vue_components()} + ${self.make_vue_app()} </body> </html> +## nb. this becomes part of the page <title> tag within <head> +## it also is used as default value for content_title() below <%def name="title()"></%def> +## nb. this is the "content title" as shown on screen, within the +## "hero bar" just below the "index title" <%def name="content_title()">${self.title()}</%def> <%def name="header_core()"> @@ -39,7 +49,10 @@ ${self.vuejs()} ${self.buefy()} ${self.fontawesome()} + ${self.hamburger_menu_js()} +</%def> +<%def name="hamburger_menu_js()"> <script> ## NOTE: this code was copied from @@ -86,14 +99,21 @@ <%def name="core_styles()"> ${self.buefy_styles()} + ${self.base_styles()} +</%def> +<%def name="buefy_styles()"> + ${h.stylesheet_link(h.get_liburl(request, 'buefy.css'))} +</%def> + +<%def name="base_styles()"> <style> - /* ****************************** */ - /* page */ - /* ****************************** */ + ############################## + ## page + ############################## - /* nb. helps force footer to bottom of screen */ + ## nb. helps force footer to bottom of screen html, body { height: 100%; } @@ -104,12 +124,14 @@ } % endif - /* nb. this refers to the "menu-sized" app title in far left of main menu */ - #global-header-title { + ## nb. this refers to the "menu-sized" app title in far left of main menu + #navbar-brand-title { font-weight: bold; } - #current-context { + #header-index-title { + display: flex; + gap: 1.5rem; padding-left: 0.5rem; } @@ -130,92 +152,44 @@ </style> </%def> -<%def name="buefy_styles()"> - ${h.stylesheet_link(h.get_liburl(request, 'buefy.css'))} -</%def> - <%def name="extra_styles()"> ${base_meta.extra_styles()} </%def> <%def name="head_tags()"></%def> -<%def name="render_whole_page_template()"> +<%def name="render_vue_template_whole_page()"> <script type="text/x-template" id="whole-page-template"> + + ## nb. the whole-page contains 3 elements: + ## 1) header-wrapper + ## 2) content-wrapper + ## 3) footer <div id="whole-page" style="height: 100%; display: flex; flex-direction: column; justify-content: space-between;"> + ## nb. the header-wrapper contains 2 elements: + ## 1) header proper (menu + index title area) + ## 2) page/content title area <div class="header-wrapper"> + ## nb. the header proper contains 2 elements: + ## 1) menu bar + ## 2) index title area <header> + + ## nb. this is the main menu bar <nav class="navbar" role="navigation" aria-label="main navigation"> - - <div class="navbar-brand"> - <a class="navbar-item" href="${url('home')}"> - <div style="display: flex; gap: 0.3rem; align-items: center;"> - ${base_meta.header_logo()} - <div id="global-header-title"> - ${base_meta.global_title()} - </div> - </div> - </a> - <a role="button" class="navbar-burger" data-target="navbar-menu" aria-label="menu" aria-expanded="false"> - <span aria-hidden="true"></span> - <span aria-hidden="true"></span> - <span aria-hidden="true"></span> - </a> - </div> - - <div class="navbar-menu" id="navbar-menu"> - <div class="navbar-start"> - - % for topitem in menus: - % if topitem['is_link']: - ${h.link_to(topitem['title'], topitem['url'], target=topitem['target'], class_='navbar-item')} - % else: - <div class="navbar-item has-dropdown is-hoverable"> - <a class="navbar-link">${topitem['title']}</a> - <div class="navbar-dropdown"> - % for item in topitem['items']: - % if item['is_menu']: - <% item_hash = id(item) %> - <% toggle = 'menu_{}_shown'.format(item_hash) %> - <div> - <a class="navbar-link" @click.prevent="toggleNestedMenu('${item_hash}')"> - ${item['title']} - </a> - </div> - % for subitem in item['items']: - % if subitem['is_sep']: - <hr class="navbar-divider" v-show="${toggle}"> - % else: - ${h.link_to("{}".format(subitem['title']), subitem['url'], class_='navbar-item nested', target=subitem['target'], **{'v-show': toggle})} - % endif - % endfor - % else: - % if item['is_sep']: - <hr class="navbar-divider"> - % else: - ${h.link_to(item['title'], item['url'], class_='navbar-item', target=item['target'])} - % endif - % endif - % endfor - </div> - </div> - % endif - % endfor - - </div><!-- navbar-start --> - ${self.render_navbar_end()} - </div> + ${self.render_navbar_brand()} + ${self.render_navbar_menu()} </nav> + ## nb. this is the "index title" area <nav class="level" style="margin: 0.5rem 0.5rem 0.5rem auto;"> - <div class="level-left"> - ## Current Context - <div id="current-context" class="level-item" - style="display: flex; gap: 1.5rem;"> + ## nb. this is the index title proper + <div class="level-left"> + <div id="header-index-title" class="level-item"> % if index_title: % if index_url: <h1 class="title">${h.link_to(index_title, index_url)}</h1> @@ -230,11 +204,12 @@ % endif % endif </div> + </div> - </div><!-- level-left --> - + ## nb. this is a utility area for the master context <div class="level-right"> + ## Configure button % if master and master.configurable and not master.configuring and master.has_perm('configure'): <div class="level-item"> <wutta-button once type="is-primary" @@ -244,11 +219,14 @@ </div> % endif - </div> <!-- level-right --> - </nav><!-- level --> + ${self.render_theme_picker()} + ${self.render_feedback_button()} + + </div> + </nav> </header> - ## Page Title + ## nb. the page / content title area (aka. hero bar) % if capture(self.content_title): <section id="content-title" class="has-background-primary"> @@ -272,10 +250,9 @@ </div> <!-- header-wrapper --> + ## nb. the page content area <div class="content-wrapper" style="flex-grow: 1; padding: 0.5rem;"> - - ## Page Body <section id="page-body" style="height: 100%;"> % if request.session.peek_flash('error'): @@ -306,10 +283,9 @@ ${self.render_this_page_component()} </div> </section> - </div><!-- content-wrapper --> - ## Footer + ## nb. the page footer <footer class="footer"> <div class="content"> ${base_meta.footer()} @@ -320,8 +296,71 @@ </script> </%def> -<%def name="render_this_page_component()"> - <this-page @change-content-title="changeContentTitle" /> +<%def name="render_navbar_brand()"> + <div class="navbar-brand"> + <a class="navbar-item" href="${url('home')}"> + <div style="display: flex; gap: 0.3rem; align-items: center;"> + ${base_meta.header_logo()} + <div id="navbar-brand-title"> + ${base_meta.global_title()} + </div> + </div> + </a> + <a role="button" class="navbar-burger" data-target="navbar-menu" aria-label="menu" aria-expanded="false"> + <span aria-hidden="true"></span> + <span aria-hidden="true"></span> + <span aria-hidden="true"></span> + </a> + </div> +</%def> + +<%def name="render_navbar_menu()"> + <div class="navbar-menu" id="navbar-menu"> + ${self.render_navbar_start()} + ${self.render_navbar_end()} + </div> +</%def> + +<%def name="render_navbar_start()"> + <div class="navbar-start"> + + % for topitem in menus: + % if topitem['is_link']: + ${h.link_to(topitem['title'], topitem['url'], target=topitem['target'], class_='navbar-item')} + % else: + <div class="navbar-item has-dropdown is-hoverable"> + <a class="navbar-link">${topitem['title']}</a> + <div class="navbar-dropdown"> + % for item in topitem['items']: + % if item['is_menu']: + <% item_hash = id(item) %> + <% toggle = 'menu_{}_shown'.format(item_hash) %> + <div> + <a class="navbar-link" @click.prevent="toggleNestedMenu('${item_hash}')"> + ${item['title']} + </a> + </div> + % for subitem in item['items']: + % if subitem['is_sep']: + <hr class="navbar-divider" v-show="${toggle}"> + % else: + ${h.link_to("{}".format(subitem['title']), subitem['url'], class_='navbar-item nested', target=subitem['target'], **{'v-show': toggle})} + % endif + % endfor + % else: + % if item['is_sep']: + <hr class="navbar-divider"> + % else: + ${h.link_to(item['title'], item['url'], class_='navbar-item', target=item['target'])} + % endif + % endif + % endfor + </div> + </div> + % endif + % endfor + + </div> </%def> <%def name="render_navbar_end()"> @@ -330,6 +369,74 @@ </div> </%def> +<%def name="render_theme_picker()"></%def> + +<%def name="render_feedback_button()"></%def> + +<%def name="render_vue_script_whole_page()"> + <script> + + const WholePage = { + template: '#whole-page-template', + computed: {}, + + mounted() { + for (let hook of this.mountedHooks) { + hook(this) + } + }, + + methods: { + + changeContentTitle(newTitle) { + this.contentTitleHTML = newTitle + }, + + toggleNestedMenu(hash) { + const key = 'menu_' + hash + '_shown' + this[key] = !this[key] + }, + + % if request.is_admin: + + startBeingRoot() { + this.$refs.startBeingRootForm.submit() + }, + + stopBeingRoot() { + this.$refs.stopBeingRootForm.submit() + }, + + % endif + }, + } + + const WholePageData = { + contentTitleHTML: ${json.dumps(capture(self.content_title))|n}, + referrer: location.href, + mountedHooks: [], + } + + ## declare nested menu visibility toggle flags + % for topitem in menus: + % if topitem['is_menu']: + % for item in topitem['items']: + % if item['is_menu']: + WholePageData.menu_${id(item)}_shown = false + % endif + % endfor + % endif + % endfor + + </script> +</%def> + +<%def name="before_content()"></%def> + +<%def name="render_this_page_component()"> + <this-page @change-content-title="changeContentTitle" /> +</%def> + <%def name="render_user_menu()"> % if request.user: <div class="navbar-item has-dropdown is-hoverable"> @@ -409,88 +516,29 @@ <%def name="render_prevnext_header_buttons()"></%def> -<%def name="declare_whole_page_vars()"> - <script> +############################## +## vue components + app +############################## - let WholePage = { - template: '#whole-page-template', - computed: {}, - - mounted() { - for (let hook of this.mountedHooks) { - hook(this) - } - }, - - methods: { - - changeContentTitle(newTitle) { - this.contentTitleHTML = newTitle - }, - - toggleNestedMenu(hash) { - const key = 'menu_' + hash + '_shown' - this[key] = !this[key] - }, - - % if request.is_admin: - - startBeingRoot() { - this.$refs.startBeingRootForm.submit() - }, - - stopBeingRoot() { - this.$refs.stopBeingRootForm.submit() - }, - - % endif - }, - } - - let WholePageData = { - contentTitleHTML: ${json.dumps(capture(self.content_title))|n}, - mountedHooks: [], - } - - ## declare nested menu visibility toggle flags - % for topitem in menus: - % if topitem['is_menu']: - % for item in topitem['items']: - % if item['is_menu']: - WholePageData.menu_${id(item)}_shown = false - % endif - % endfor - % endif - % endfor - - </script> +<%def name="render_vue_templates()"> + ${self.render_vue_template_whole_page()} + ${self.render_vue_script_whole_page()} </%def> -<%def name="modify_whole_page_vars()"></%def> +<%def name="modify_vue_vars()"></%def> -<%def name="finalize_whole_page_vars()"></%def> - -<%def name="make_whole_page_component()"> +<%def name="make_vue_components()"> ${make_wutta_components()} - ${self.render_whole_page_template()} - ${self.declare_whole_page_vars()} - ${self.modify_whole_page_vars()} - ${self.finalize_whole_page_vars()} - <script> - WholePage.data = function() { return WholePageData } Vue.component('whole-page', WholePage) - </script> </%def> -<%def name="make_whole_page_app()"> +<%def name="make_vue_app()"> <script> - new Vue({ el: '#app' }) - </script> </%def> diff --git a/src/wuttaweb/templates/base_meta.mako b/src/wuttaweb/templates/base_meta.mako index c65e68c..65d1ede 100644 --- a/src/wuttaweb/templates/base_meta.mako +++ b/src/wuttaweb/templates/base_meta.mako @@ -1,8 +1,6 @@ ## -*- coding: utf-8; -*- -<%def name="app_title()">${app.get_title()}</%def> - -<%def name="global_title()">${self.app_title()}</%def> +<%def name="global_title()">${app.get_title()}</%def> <%def name="extra_styles()"></%def> diff --git a/src/wuttaweb/templates/configure.mako b/src/wuttaweb/templates/configure.mako index 58b707e..d430672 100644 --- a/src/wuttaweb/templates/configure.mako +++ b/src/wuttaweb/templates/configure.mako @@ -134,8 +134,8 @@ </b-notification> </%def> -<%def name="modify_this_page_vars()"> - ${parent.modify_this_page_vars()} +<%def name="modify_vue_vars()"> + ${parent.modify_vue_vars()} <script> % if simple_settings is not Undefined: diff --git a/src/wuttaweb/templates/form.mako b/src/wuttaweb/templates/form.mako index 9a0d21e..2baf95a 100644 --- a/src/wuttaweb/templates/form.mako +++ b/src/wuttaweb/templates/form.mako @@ -9,19 +9,16 @@ </div> </%def> -<%def name="render_this_page_template()"> - ${parent.render_this_page_template()} +<%def name="render_vue_templates()"> + ${parent.render_vue_templates()} % if form is not Undefined: ${form.render_vue_template()} % endif </%def> -<%def name="finalize_this_page_vars()"> - ${parent.finalize_this_page_vars()} +<%def name="make_vue_components()"> + ${parent.make_vue_components()} % if form is not Undefined: ${form.render_vue_finalize()} % endif </%def> - - -${parent.body()} diff --git a/src/wuttaweb/templates/master/index.mako b/src/wuttaweb/templates/master/index.mako index 6731f65..a16aced 100644 --- a/src/wuttaweb/templates/master/index.mako +++ b/src/wuttaweb/templates/master/index.mako @@ -12,18 +12,20 @@ % endif </%def> -<%def name="render_this_page_template()"> - ${parent.render_this_page_template()} +<%def name="render_vue_templates()"> + ${parent.render_vue_templates()} + ${self.render_vue_template_grid()} +</%def> + +<%def name="render_vue_template_grid()"> % if grid is not Undefined: ${grid.render_vue_template()} % endif </%def> -<%def name="finalize_this_page_vars()"> - ${parent.finalize_this_page_vars()} +<%def name="make_vue_components()"> + ${parent.make_vue_components()} % if grid is not Undefined: ${grid.render_vue_finalize()} % endif </%def> - -${parent.body()} diff --git a/src/wuttaweb/templates/page.mako b/src/wuttaweb/templates/page.mako index c014e06..840e918 100644 --- a/src/wuttaweb/templates/page.mako +++ b/src/wuttaweb/templates/page.mako @@ -1,45 +1,29 @@ ## -*- coding: utf-8; -*- <%inherit file="/base.mako" /> -<%def name="context_menu_items()"> - % if context_menu_list_items is not Undefined: - % for item in context_menu_list_items: - <li>${item}</li> - % endfor - % endif -</%def> - <%def name="page_content()"></%def> -<%def name="render_this_page()"> - <div style="display: flex;"> - - <div class="this-page-content" style="flex-grow: 1;"> - ${self.page_content()} - </div> - - <ul id="context-menu"> - ${self.context_menu_items()} - </ul> - - </div> +<%def name="render_vue_templates()"> + ${parent.render_vue_templates()} + ${self.render_vue_template_this_page()} + ${self.render_vue_script_this_page()} </%def> -<%def name="render_this_page_template()"> +<%def name="render_vue_template_this_page()"> <script type="text/x-template" id="this-page-template"> <div style="height: 100%;"> - ${self.render_this_page()} + ${self.page_content()} </div> </script> </%def> -<%def name="declare_this_page_vars()"> - <script type="text/javascript"> +<%def name="render_vue_script_this_page()"> + <script> - let ThisPage = { + const ThisPage = { template: '#this-page-template', props: { - configureFieldsHelp: Boolean, + ## configureFieldsHelp: Boolean, }, computed: {}, watch: {}, @@ -51,31 +35,16 @@ }, } - let ThisPageData = { - } + const ThisPageData = {} </script> </%def> -<%def name="modify_this_page_vars()"></%def> - -<%def name="finalize_this_page_vars()"></%def> - -<%def name="make_this_page_component()"> - ${self.declare_this_page_vars()} - ${self.modify_this_page_vars()} - ${self.finalize_this_page_vars()} - - <script type="text/javascript"> - +<%def name="make_vue_components()"> + ${parent.make_vue_components()} + <script> ThisPage.data = function() { return ThisPageData } - Vue.component('this-page', ThisPage) ## <% request.register_component('this-page', 'ThisPage') %> - </script> </%def> - - -${self.render_this_page_template()} -${self.make_this_page_component()}