Code Monkey home page Code Monkey logo

wagtail-livepreview's Introduction

Wagtail Live Preview

Wagtail Live Preview lets you view your page changes as you make them in the Wagtail Admin.

⚠️⚠️⚠️

⚠️ This project is not supported anymore: Wagtail CMS 5+ comes with built-in live-preview. It is recommended to use Wagtail's naturally supported features rather than 3rd party packages.

⚠️⚠️⚠️

Using React or Vue? This won't work for you, nor was it designed to. This Live Preview package is designed for simple Wagtail websites.

How it works

Tell it how often to save a snapshot of the page you're working on and how often to poll for updates in the Live Preview.

It does not piggy back on Wagtails Revision system, but you can tell it to save a page revision every x number of saves so you never accidentally lose your work (or if you just want to log your progress and maybe revert back to a previous content iteration).

The package itself is called wagtail-livepreview to let everyone know this is a Wagtail specific package. But the code references livepreview instead of wagtail_livepreview as to not confuse Wagtail features with what's in this package.

Installation

  1. Install the package
pip install wagtail-livepreview
  1. Add it to your INSTALLED_APPS above the 'wagtail.admin' app.
INSTALLED_APPS = [
    # ...
    'livepreview',
    # ...
    'wagtail.admin',
]
  1. Add {% load livepreview_tags %} to your base.html template. And add {% livepreview_js %} right above your </body> tag in base.html
{% load static wagtailuserbar livepreview_tags %}

<!DOCTYPE html>
<html class="no-js" lang="en">
    <head>
        ...
    </head>

    <body class="{% block body_class %}{% endblock %}">
        ...

        {% livepreview_js %}
    </body>
</html>
  1. You'll need to apply migrations.
python manage.py migrate

Hooks

You can take an action before and after a Live Preview using a generic Wagtail hook.

@hooks.register('after_live_preview_save')
def after_live_preview_save(request, page):
    """Event to happen before the live preview is served."""
    print(page.id)


@hooks.register('before_live_preview_save')
def before_live_preview_save(request, page):
    """Event to happen after the live preview is served."""
    print(page.id)

Caution: It's a bad idea to provide a process intensive task in these hooks since these hooks may end up being called as frequently as once per second. It might be best to offload your tasks in these hooks to a task runner.

Tips

Checking if a view is a Live Preview or not

You'll want to adjust your template so you aren't triggering your analytics every second. You can prevent this with:

{% if not livepreview %}
    .. analytics in here
{% else %}
    <div id="warning">This is a live preview</div>
{% endif %}

You can also use {{ request.livepreview }} in your template to check against the request.

Settings

Global Settings

# base settings.py

# How often (in milliseconds) should the livepreview check for page updates? Default is 1000ms.
LIVEPREVIEW_TIMEOUT = 1000
# If you'd like to turn on auto-revision saving every x number of Live Preview saves, set this as True. Default is False.
LIVEPREVIEW_SAVE_AS_REVISIONS = False
# How many Live Preview saves should happen before a new revision is automatically saved? Default is 10. Requires LIVEPREVIEW_SAVE_AS_REVISIONS = True.
LIVEPREVIEW_SAVE_REVISION_COUNT = 10
# Render Live Previews into a temporary file, and attempt to serve that file. Default is true.
# If True, LIVEPREVIEW_TIMEOUT can be as low as 250ms.
# If False, the minimum LIVEPREVIEW_TIMEOUT is 1000ms.
LIVEPREVIEW_USE_FILE_RENDERING = True

Model Settings

You can disable Live Preview for specific page models. For example, you might have a simple Blog Index Page with just a title field. Or a page that redirects to another page. In these scenarios you might not want Live Preview enabled.

class YourPage(Page):
    # ...
    LIVEPREVIEW_DISABLED = True  # Disable Live Preview on a per-model basis

Contributing

Feel free to open a PR. I'm not overly picky about how things are done as long as it works and it's kept relatively simple.

The JavaScript can use a lot of improvements (small and large) so that'd be a great place to start.

Contributors

@todos

If anyone wants to get involved and pick off a few of these tasks, that'd be awesome. But no pressure.

  • Implement proper http protocol responses
  • Remove jQuery in favor of vanilla JS
  • Put the iframe in the content_panels ONLY tab.
  • Make the iframe be 100% height of the content section
  • Add better JavaScript error handling and events
  • When LIVEPREVIEW_USE_FILE_RENDERING is enabled, save the LivePreview file with minified html (Not using middleware, and respects spacing in elements like <pre> and <textarea>)

wagtail-livepreview's People

Contributors

jkevingutierrez avatar kalobtaulien avatar lunatikdev avatar quadric avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

wagtail-livepreview's Issues

2.10 migration

Wagtail 2.10 will have lots of template changes and might not be compatible with this package.

I'd LOVE if someone could test this out with 2.10 and report back (may need to work on #15 first).

Live preview in separate window does not work when iframe is closed

When i click "live preview" button it opens a new window with page preview. It refreshes in "real time" when i modify my page form so this works OK - but it stops working when i "hide" the iframe on right side of page form. If i show it again the separate full windows refreshes again.

// EDIT
OK i see that when i turn off iframe form does not make POST to live_preview thats why this separate full windows does not see changes when refreshes body.

Do you have any idea why it happens and how to fix it?

Can't delete a page because of an IntegrityError

Can't delete a page that is referenced in the table livepreview_livepreviewrevision

django.db.utils.IntegrityError: update or delete on table "wagtailcore_page" violates foreign key constraint "livepreview_liveprev_page_id_a0bcd10f_fk_wagtailco" on table "livepreview_livepreviewrevision"

File "/usr/local/lib/python3.8/site-packages/django/core/handlers/exception.py", line 34, in inner response = get_response(request) 
File "/usr/local/lib/python3.8/site-packages/django/core/handlers/base.py", line 115, in _get_response response = self.process_exception_by_middleware(e, request) 
File "/usr/local/lib/python3.8/site-packages/django/core/handlers/base.py", line 113, in _get_response response = wrapped_callback(request, *callback_args, **callback_kwargs) 
File "/usr/local/lib/python3.8/site-packages/django/views/decorators/cache.py", line 44, in _wrapped_view_func response = view_func(request, *args, **kwargs) 
File "/usr/local/lib/python3.8/site-packages/wagtail/admin/urls/__init__.py", line 110, in wrapper return view_func(request, *args, **kwargs) 
File "/usr/local/lib/python3.8/site-packages/wagtail/admin/auth.py", line 188, in decorated_view return view_func(request, *args, **kwargs) 
File "/usr/local/lib/python3.8/site-packages/wagtail/admin/views/pages.py", line 792, in delete return redirect(next_url) 
File "/usr/local/lib/python3.8/site-packages/django/db/transaction.py", line 232, in __exit__ connection.commit() 
File "/usr/local/lib/python3.8/site-packages/django/utils/asyncio.py", line 26, in inner return func(*args, **kwargs) 
File "/usr/local/lib/python3.8/site-packages/django/db/backends/base/base.py", line 267, in commit self._commit()
File "/usr/local/lib/python3.8/site-packages/django/db/backends/base/base.py", line 243, in _commit return self.connection.commit() 
File "/usr/local/lib/python3.8/site-packages/django/db/utils.py", line 90, in __exit__ raise dj_exc_value.with_traceback(traceback) from exc_value 
File "/usr/local/lib/python3.8/site-packages/django/db/backends/base/base.py", line 243, in _commit return self.connection.commit() django.db.utils.IntegrityError: update or delete on table "wagtailcore_page" violates foreign key constraint "livepreview_liveprev_page_id_a0bcd10f_fk_wagtailco" on table "livepreview_livepreviewrevision"

Not compatible to Django 3

File "/Users/andy/projects/po-website/.venv/lib/python3.8/site-packages/livepreview/wagtail_hooks.py", line 9, in

from django.contrib.staticfiles.templatetags.staticfiles import static

ModuleNotFoundError: No module named 'django.contrib.staticfiles.templatetags'

Add options to hide and disable livepreview window

There is a Toggle live preview button that shows and hides the livepreview window, but when you load a page it always shows the window by default. It would be great to have an option in settings HIDE_LIVEPREVIEW to hide the window by default when someone is editing a page.

Also, sometimes you want to show livepreview in some environments (Staging and Dev) and hide it in others (Production). It would be very useful to have another option in settings DISABLE_LIVEPREVIEW to disable livepreview globally.

Live preview is removing script tags

Livepreview is removing all the script tags in the generated HTML. (https://github.com/KalobTaulien/wagtail-livepreview/blob/master/livepreview/static/livepreview/js/livepreview_fe.js#L4)

Javascript could be used to position elements, to apply CSS styles, to add lazy loading, etc. Removing all the scripts from the page could greatly affect the view of the page (even for simple sites that don't use any JS framework).

It would be great to stop removing all the script tags in the HTML, as this can affect the preview of the pages.

Maybe the stripScripts function should only remove the scripts inside the div with the class js-livepreview-script?

Even when LIVEPREVIEW_USE_FILE_RENDERING is set to False - application tries to create a folder

Even when we set LIVEPREVIEW_USE_FILE_RENDERING=False application tries to make a folder to store rendered page. It could be easily fixed by changing this code

in views.py line 123

        file_name = self.get_live_preview_file_name(page_id, request.user.id)
        use_file_rendering = getattr(settings, "LIVEPREVIEW_USE_FILE_RENDERING", True)
        if use_file_rendering and os.path.isfile(file_name):
            with open(file_name, 'r') as file:
                page_content = file.read()
                return HttpResponse(page_content)

to

        use_file_rendering = getattr(settings, "LIVEPREVIEW_USE_FILE_RENDERING", True)
        if use_file_rendering:
            file_name = self.get_live_preview_file_name(page_id, request.user.id)
            if os.path.isfile(file_name):
                with open(file_name, 'r') as file:
                    page_content = file.read()
                    return HttpResponse(page_content)

request.site is None in live_preview

Hey.

This app is a nice idea and i'd like to use it in my project (and maybe contribute in a future with some improvements) but currently i have a problem with page in "live preview" mode.

The problem is than in template {{ request.site }} returns None when page is rendered by live_preview endpoint. I have no idea where to find a problem.

Wagtail's vanilla "preview" endpoint works well. Do you have any clues?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.