Skip to content

Commit

Permalink
Merge 45830a4 into 4defec5
Browse files Browse the repository at this point in the history
  • Loading branch information
Mojken committed Apr 1, 2022
2 parents 4defec5 + 45830a4 commit d346a1e
Show file tree
Hide file tree
Showing 27 changed files with 1,910 additions and 65 deletions.
1 change: 1 addition & 0 deletions djedi/__init__.py
Expand Up @@ -49,6 +49,7 @@ def configure():
"cio.plugins.txt.TextPlugin",
"cio.plugins.md.MarkdownPlugin",
"djedi.plugins.img.ImagePlugin",
"djedi.plugins.list.ListPlugin",
],
"THEME": "darth",
}
Expand Down
30 changes: 21 additions & 9 deletions djedi/admin/api.py
Expand Up @@ -4,12 +4,14 @@
from django.http import Http404, HttpResponse, HttpResponseBadRequest
from django.template.response import TemplateResponse
from django.utils.http import urlunquote
from django.utils.safestring import mark_safe
from django.views.decorators.cache import never_cache
from django.views.decorators.clickjacking import xframe_options_exempt
from django.views.decorators.csrf import csrf_exempt
from django.views.generic import View

import cio
from cio.node import Node
from cio.plugins import plugins
from cio.plugins.exceptions import UnknownPlugin
from cio.utils.uri import URI
Expand Down Expand Up @@ -173,11 +175,14 @@ def post(self, request, ext):
try:
plugin = plugins.get(ext)
data, meta = self.get_post_data(request)
data = plugin.load(data)
uri = URI(ext=ext)
node = Node(uri=uri, content=data)
data = plugin.load_node(node)
node.content = data
except UnknownPlugin:
raise Http404
else:
content = plugin.render(data)
content = plugin.render_node(node, data)
return self.render_to_response(content)


Expand All @@ -187,12 +192,7 @@ class NodeEditor(JSONResponseMixin, DjediContextMixin, APIView):
def get(self, request, uri):
try:
uri = self.decode_uri(uri)
uri = URI(uri)
plugin = plugins.resolve(uri)
plugin_context = self.get_context_data(uri=uri)

if isinstance(plugin, DjediPlugin):
plugin_context = plugin.get_editor_context(**plugin_context)
plugin_context = self.get_plugin_context(request, uri)

except UnknownPlugin:
raise Http404
Expand All @@ -208,17 +208,29 @@ def post(self, request, uri):

context = cio.load(node.uri)
context["content"] = node.content
context.update(self.get_plugin_context(request, context["uri"]))

if request.is_ajax():
return self.render_to_json(context)
else:
return self.render_plugin(request, context)

def get_plugin_context(self, request, uri):
uri = URI(uri)
plugin = plugins.resolve(uri)

context = {"uri": uri, "plugin": uri.ext}
if isinstance(plugin, DjediPlugin):
context = plugin.get_editor_context(request, **context)

context["uri"] = mark_safe(context["uri"])
return context

def render_plugin(self, request, context):
return TemplateResponse(
request,
[
"djedi/plugins/%s/editor.html" % context["uri"].ext,
"djedi/plugins/%s/editor.html" % context["plugin"],
"djedi/plugins/base/editor.html",
],
self.get_context_data(**context),
Expand Down
3 changes: 3 additions & 0 deletions djedi/admin/mixins.py
@@ -1,9 +1,11 @@
import simplejson as json
from django.conf import settings as django_settings
from django.http import HttpResponse
from django.utils.safestring import mark_safe

import djedi
from cio.conf import settings
from cio.plugins import plugins

# TODO: Switch simplejson to ujson or other?

Expand Down Expand Up @@ -38,5 +40,6 @@ def get_context_data(self, **context):

context["THEME"] = theme
context["VERSION"] = djedi.__version__
context["PLUGINS"] = mark_safe(json.dumps(list(plugins.plugins.keys())))

return context
4 changes: 2 additions & 2 deletions djedi/plugins/base.py
Expand Up @@ -2,8 +2,8 @@


class DjediPlugin(BasePlugin):
def get_editor_context(self, **kwargs):
def get_editor_context(self, request, **context):
"""
Returns custom context
"""
return kwargs
return context
5 changes: 3 additions & 2 deletions djedi/plugins/form.py
Expand Up @@ -43,8 +43,9 @@ class FormsBasePlugin(DjediPlugin):
def forms(self):
return {}

def get_editor_context(self, **context):
context.update({"forms": {tab: form() for tab, form in self.forms.items()}})
def get_editor_context(self, request, **context):
if not request.is_ajax():
context.update({"forms": {tab: form() for tab, form in self.forms.items()}})

return context

Expand Down
172 changes: 172 additions & 0 deletions djedi/plugins/list.py
@@ -0,0 +1,172 @@
import json

import cio
from cio.node import Node
from cio.plugins import plugins

from .base import DjediPlugin


class ListPlugin(DjediPlugin):
ext = "list"

def get_editor_context(self, request, **context):
uri = context["uri"]
plugin_ext = self.get_query_param(uri, "plugin")
if plugin_ext:
context["plugin"] = plugin_ext
plugin = plugins.get(plugin_ext)
if isinstance(plugin, DjediPlugin):
context.update(plugin.get_editor_context(request, **context))

return context

def load(self, content):
if content:
try:
return json.loads(content)
except ValueError:
pass
return {"direction": "col", "children": []}

def load_node(self, node):
list_data = self.load(node.content)

# Root data
if self.is_leaf_list_node(node.uri):
return list_data

# Child data
child_node, key = self.get_child_node(node.uri, list_data)
plugin = self.resolve_child_plugin(child_node.uri)

return plugin.load_node(child_node)

def render_node(self, node, data):
if not self.is_leaf_list_node(node.uri):
child_plugin = self.resolve_child_plugin(node.uri)
if child_plugin:
child_uri, _ = self.get_child_uri(node.uri)
return child_plugin.render_node(Node(uri=child_uri), data)

return "".join(self.stream_node(node, data))

def stream_node(self, node, data):
yield '<ul class="djedi-list djedi-list--{direction}">'.format(**data)
for child in data["children"]:
ext = child["plugin"]
child_uri = node.uri.clone(query={"plugin": [ext], "key": [child["key"]]})
child_node = Node(uri=child_uri, content=child["data"])
plugin = plugins.get(ext)
content = plugin.load_node(child_node)
yield '<li class="djedi-plugin--{plugin}" id="{key}">'.format(**child)
yield plugin.render_node(child_node, content) or ""
yield "</li>"
yield "</ul>"

def resolve_child_plugin(self, uri):
if self.is_nested(uri):
ext = self.ext
else:
ext = self.get_query_param(uri, "plugin")

return plugins.get(ext or self.ext)

def find_child(self, data, key):
if not key:
return None

for child in data["children"]:
if child["key"] == key:
return child

return None

def get_child_node(self, uri, parent_data, default=None):
# TODO: modify uri or content instead of new Nodes?
child_uri, key = self.get_child_uri(uri)
child = self.find_child(parent_data, key)
content = child["data"] if child else default
return Node(uri=child_uri, content=content), key

def get_query_param(self, uri, param):
value = (uri.query or {}).get(param)
return value[0] if value else ""

def is_nested(self, uri):
return bool(self.get_query_param(uri, "key"))

def get_child_key(self, uri):
key = self.get_query_param(uri, "key")
if not key:
return None, None

key, _, rest = key.partition("_")
return key, rest

def get_child_uri(self, uri):
key, rest = self.get_child_key(uri)

if uri.query:
query = dict(uri.query)
if not rest:
query.pop("key", None)
else:
query["key"] = [rest]
uri = uri.clone(query=query)

return uri, key

def is_leaf_list_node(self, uri):
plugin = self.get_query_param(uri, "plugin")
return not plugin or plugin == self.ext and not self.is_nested(uri)

def save_node(self, node):
if not self.get_query_param(node.uri, "plugin"):
return node

root_node = cio.load(node.uri.clone(query=None))
root_data = root_node["data"] or self.load(None)

node.content = self.save_child(
node.content, parent_node=node, parent_data=root_data
) # TODO: deep clone data?

return node

def save_child(self, leaf_data, parent_node, parent_data):
child_node, key = self.get_child_node(
parent_node.uri, parent_data, default=parent_node.content
)

plugin = self.resolve_child_plugin(child_node.uri)
if plugin.ext == self.ext:
if not self.is_nested(child_node.uri):
child_content = leaf_data
else:
child_data = self.load(child_node.content)
child_content = self.save_child(
leaf_data, parent_node=child_node, parent_data=child_data
)
else:
child_node.content = leaf_data
child_node = plugin.save_node(child_node)
child_content = child_node.content

child = self.find_child(parent_data, key)

if child:
child["data"] = child_content
else:
parent_data["children"].append(
{
"key": key,
"plugin": plugin.ext,
"data": child_content,
}
)

return self.save(parent_data)

def save(self, content):
return json.dumps(content)
8 changes: 4 additions & 4 deletions djedi/static/djedi/cms/js/cms.coffee
Expand Up @@ -35,7 +35,7 @@ class Settings


################################################[ NODE ]##############################################################
class Node
class window.Node

selected: no

Expand Down Expand Up @@ -253,7 +253,7 @@ class Page


################################################[ PLUGIN ]############################################################
class Plugin
window.Plugin = class Plugin

constructor: (@node) ->
@uri = @node.uri.valueOf()
Expand Down Expand Up @@ -388,5 +388,5 @@ class CMS
else
@page.$cms.css style


new CMS
window.makeCms = ->
new CMS
10 changes: 6 additions & 4 deletions djedi/static/djedi/cms/js/cms.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit d346a1e

Please sign in to comment.