Skip to content

Commit

Permalink
Add the possibility of updating html through morphs
Browse files Browse the repository at this point in the history
  • Loading branch information
jonathan-s committed Dec 29, 2020
1 parent 83e8c48 commit a1727f5
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 12 deletions.
8 changes: 8 additions & 0 deletions cypress/integration/websocket_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,12 @@ describe("Integration tests", () => {
cy.get('#decrementor').click()
cy.get('#decrementor-counter').should('have.text', '-1')
})

it("can send a morph in a reflex", () => {
cy.visit('/test')
cy.wait(200)
cy.get('#morph-button').click()

cy.get('#morph').should('have.text', 'I got morphed!')
})
})
28 changes: 24 additions & 4 deletions sockpuppet/consumer.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,14 +148,30 @@ def reflex_message(self, data, **kwargs):
url = data['url']
selectors = data['selectors'] if data['selectors'] else ['body']
target = data['target']
identifier = data['identifier']
reflex_name, method_name = target.split('#')
reflex_name = classify(reflex_name)
arguments = data['args'] if data.get('args') else []
params = dict(parse_qsl(data['formData']))
element = Element(data['attrs'])

# TODO can be removed once stimulus-reflex has increased a couple of versions
permanent_attribute_name = data.get('permanent_attribute_name')
if not permanent_attribute_name:
# Used in stimulus-reflex >= 3.4
permanent_attribute_name = data['permanentAttributeName']

try:
ReflexClass = self.reflexes.get(reflex_name)
reflex = ReflexClass(self, url=url, element=element, selectors=selectors, params=params)
reflex = ReflexClass(
self, url=url,
element=element,
selectors=selectors,
identifier=identifier,
params=params,
reflex_id=data['reflexId'],
permanent_attribute_name=permanent_attribute_name
)
self.delegate_call_to_reflex(reflex, method_name, arguments)
except TypeError:
if not self.reflexes.get(reflex_name):
Expand Down Expand Up @@ -223,6 +239,10 @@ def receive_json(self, data, **kwargs):
print('Unsupported')

def render_page_and_broadcast_morph(self, reflex, selectors, data):
if reflex.is_morph:
# The reflex has already sent a message so consumer doesn't need to.
return

html = self.render_page(reflex)
if html:
self.broadcast_morphs(selectors, data, html, reflex)
Expand Down Expand Up @@ -252,7 +272,7 @@ def render_page(self, reflex):
def broadcast_morphs(self, selectors, data, html, reflex):
document, selectors = get_document_and_selectors(html, selectors)

channel = Channel(reflex.get_channel_id(), identifier=data['identifier'])
broadcaster = Channel(reflex.get_channel_id(), identifier=data['identifier'])
logger.debug('Broadcasting to %s', reflex.get_channel_id())

# TODO can be removed once stimulus-reflex has increased a couple of versions
Expand All @@ -264,14 +284,14 @@ def broadcast_morphs(self, selectors, data, html, reflex):
for selector in selectors:
# cssselect has an attribute css
plain_selector = getattr(selector, 'css', selector)
channel.morph({
broadcaster.morph({
'selector': plain_selector,
'html': parse_out_html(document, selector),
'children_only': True,
'permanent_attribute_name': permanent_attribute_name,
'stimulus_reflex': {**data}
})
channel.broadcast()
broadcaster.broadcast()

def delegate_call_to_reflex(self, reflex, method_name, arguments):
method = getattr(reflex, method_name)
Expand Down
60 changes: 52 additions & 8 deletions sockpuppet/reflex.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,34 @@
from django.template.loader import render_to_string
from django.template.backends.django import Template
from django.test import RequestFactory

from .channel import Channel

PROTECTED_VARIABLES = [
'consumer',
'element',
'is_morph',
'selectors',
'session',
'url',
]


class Reflex:
def __init__(self, consumer, url, element, selectors, params):
def __init__(
self, consumer, url, element, selectors, params, identifier='',
permanent_attribute_name=None, reflex_id=None
):
self.consumer = consumer
self.url = url
self.element = element
self.selectors = selectors
self.session = consumer.scope['session']
self.params = params

def get_channel_id(self):
'''
Override this to make the reflex send to a different channel
other than the session_key of the user
'''
return self.session.session_key
self.identifier = identifier
self.is_morph = False
self.reflex_id = reflex_id
self.permanent_attribute_name = permanent_attribute_name

@property
def request(self):
Expand All @@ -37,3 +42,42 @@ def request(self):
def reload(self):
"""A default reflex to force a refresh"""
pass

def get_channel_id(self):
'''
Override this to make the reflex send to a different channel
other than the session_key of the user
'''
return self.session.session_key

def morph(self, selector='', html='', template='', context={}):
"""
If a morph is executed without any arguments, nothing is executed
and the reflex won't send over any data to the frontend.
"""
self.is_morph = True
no_arguments = [not selector, not html, (not template and not context)]
if all(no_arguments) and not selector:
# an empty morph, nothing is sent ever.
return

if html:
html = html
elif isinstance(template, Template):
html = template.render(context)
else:
html = render_to_string(template, context)

broadcaster = Channel(self.get_channel_id(), identifier=self.identifier)
broadcaster.morph({
'selector': selector,
'html': html,
'children_only': True,
'permanent_attribute_name': self.permanent_attribute_name,
'stimulus_reflex': {
'morph': 'selector',
'reflexId': self.reflex_id,
'url': self.url
}
})
broadcaster.broadcast()
5 changes: 5 additions & 0 deletions tests/example/reflexes/example_reflex.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,8 @@ def change_word(self):
class FormReflex(Reflex):
def submit(self):
self.text_output = self.request.POST['text-input']


class MorphReflex(Reflex):
def morph_me(self):
self.morph('#morph', 'I got morphed!')
5 changes: 5 additions & 0 deletions tests/example/templates/example.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,9 @@
</div>

<span id="text-output">{{ text_output }}</span>


<button id="morph-button" data-reflex="click->MorphReflex#morph_me">Morph me</button>
<span id="morph"></span>

</body>

0 comments on commit a1727f5

Please sign in to comment.