Created
August 5, 2021 17:15
-
-
Save eoghanmurray/c3cd4d020ee05dd63d143fbc0b324692 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from cssutils import parseStyle | |
def find_node_by_id(tree, search_id): | |
recursive_priority = [] | |
for childNode in tree['childNodes']: | |
if childNode['id'] == search_id: | |
return childNode | |
elif 'childNodes' in childNode: | |
if childNode['id'] < search_id: | |
# take advantage of depth first ordering | |
recursive_priority.insert(0, childNode) | |
else: | |
recursive_priority.append(childNode) | |
for childNode in recursive_priority: | |
res = find_node_by_id(childNode, search_id) | |
if res: | |
return res | |
def apply_mutation(snapshot, mutation): | |
for add in mutation['data']['adds']: | |
parent = find_node_by_id( | |
snapshot['data']['node'], | |
add['parentId'], | |
) | |
if not parent: | |
raise UnhandledMutation( | |
f"could not find add parent {add['parentId']}" | |
) | |
if add['nextId'] is None: | |
parent['childNodes'].append(add['node']) | |
continue | |
for i, child in enumerate(parent['childNodes']): | |
if child['id'] == add['nextId']: | |
parent['childNodes'] = \ | |
parent['childNodes'][:i] + \ | |
[add['node']] + \ | |
parent['childNodes'][i:] | |
break | |
else: | |
raise UnhandledMutation( | |
f"could not find add nextId {add['nextId']}" | |
) | |
for attrNode in mutation['data']['attributes']: | |
node = find_node_by_id( | |
snapshot['data']['node'], | |
attrNode['id']) | |
if not node: | |
raise UnhandledMutation( | |
f"could not find node for attribute mutation {attrNode['id']}" | |
) | |
for attrKey in attrNode['attributes']: | |
value = attrNode['attributes'][attrKey] | |
if value is None: | |
del node['attributes'][attrKey] | |
elif isinstance(value, str): | |
# update | |
node['attributes'][attrKey] = value | |
elif attrKey == 'style': | |
# note: the parsing here modifies (normalises) other style | |
# rules not included in the mutation. Hoping it's okay as | |
# would be similar to how browser interprets the rules | |
style_rule = parseStyle( | |
node['attributes'].get('style', ''), | |
validate=False, | |
) | |
for k, v in value.items(): | |
if v is False: | |
style_rule.removeProperty(k) | |
elif isinstance(v, list): | |
style_rule.setProperty(k, v[0], v[1]) | |
else: | |
if v is False or v is None or not v: | |
import pdb; pdb.set_trace(); | |
style_rule[k] = v | |
node['attributes'][attrKey] = style_rule.cssText.replace('\n', ' ') | |
for text in mutation['data']['texts']: | |
import pdb; pdb.set_trace(); | |
node = find_node_by_id(snapshot['data']['node'], text['id']) | |
if not node: | |
raise UnhandledMutation( | |
f"could not find node for text mutation {attrNode['id']}" | |
) | |
node['textContent'] = text['value'] | |
for rem in mutation['data']['removes']: | |
parent = find_node_by_id( | |
snapshot['data']['node'], | |
rem['parentId']) | |
if not parent: | |
raise UnhandledMutation( | |
f"could not find remove parent {add['parentId']}" | |
) | |
for i, child in enumerate(parent['childNodes']): | |
if child['id'] == rem['id']: | |
parent['childNodes'] = \ | |
parent['childNodes'][:i] + \ | |
parent['childNodes'][i+1:] | |
break | |
else: | |
raise UnhandledMutation( | |
f"could not find remove by id {rem['id']}" | |
) | |
class UnhandledMutation(Exception): | |
pass |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment