Skip to content

Instantly share code, notes, and snippets.

@eoghanmurray
Created August 5, 2021 17:15
Show Gist options
  • Save eoghanmurray/c3cd4d020ee05dd63d143fbc0b324692 to your computer and use it in GitHub Desktop.
Save eoghanmurray/c3cd4d020ee05dd63d143fbc0b324692 to your computer and use it in GitHub Desktop.
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