Commit 6f3eb618 authored by ∞'s avatar 💻

Merge branch 'fix_example' into 'master'

Fix example

See merge request !1
parents e1ff1b4a 27646305
from chp.pyreact import *
from .pyreact import *
def Div(props, children):
children = children or []
return ce('div', props, children)
def Button(props, children):
props = props or []
props.append(
cp('type', 'button'))
children = children or []
return ce('div', props, children)
return ce('button', props, children)
def Script(string = ""):
def Script(string=""):
return ce('script', [], string)
def ScriptBefore(children, script_text):
children = children or []
script = [Script(script_text)]
children = script.append(children)
children = script.append(children)
return Div([], children)
def Grid(children):
children = children or []
def Form(children, action="#", method="POST"):
props = [
cp('class', 'mdc-layout-grid__inner')
cp('action', action),
cp('method', method),
]
return Div(props, children)
def Row(children):
children = children or []
props = [
cp('class', 'mdc-layout-grid__inner')
]
return Div(props, children)
return ce('form', props, children)
def Cell(children):
children = children or []
props = [
cp('class', 'mdc-layout-grid__cell')
]
return Div(props, children)
def Errors():
props = []
children='''
children = '''
'''
return Div(props, children)
def Form(children):
props = [
cp('class', 'mdc-layout-grid__cell')
]
errors=Errors()
children.append(errors)
return ce('form', props, children)
def Field(children):
children = children or []
def Input(el_type="text", el_id=None):
props = [
cp('class', 'mdc-layout-field')
cp('type', el_type),
]
return Div(props, children)
if id is not None:
props.append(
cp('id', el_id),
)
return ce('input', props, [])
def Checkbox(is_checked):
props = [
cp('class', 'mdc-checkbox__native-control'),
cp('type', 'checkbox'),
cp('id', '{{ id }}'),
cp('checked' if is_checked else '', ''),
]
return ce('input', props, [])
def Checkbox(is_checked=False, el_id=None):
ast = Input("checkbox", el_id)
if is_checked:
ast["props"].append(
cp('checked', "")
)
return ast
def Label(name):
def c(context):
props = [
]
return ce('label', props, context["label"] + " " + name)
return c
def CheckboxField(isChecked):
def c(context):
children = []
def Label(label, el_for=None):
props = []
if el_for is not None:
props = [
cp('class', 'mdc-form-field')
cp("for", el_for)
]
children.append(Div(
[cp("class", "mdc-checkbox")],
[
Checkbox(isChecked),
Div(
[cp("class", "mdc-checkbox-background")],
[]
),
Label('Checkbox'),
Label(context["label"])
]
))
return Div(props, children)
return c
return ce('label', props, label)
# def Label(name):
# def c(context):
# props = [
# ]
# return ce('label', props, context["label"] + " " + name)
# return c
# def CheckboxField(isChecked):
# def c(context):
# children = []
# props = [
# cp('class', 'mdc-form-field')
# ]
# children.append(Div(
# [cp("class", "mdc-checkbox")],
# [
# Checkbox(isChecked),
# Div(
# [cp("class", "mdc-checkbox-background")],
# []
# ),
# Label('Checkbox'),
# Label(context["label"])
# ]
# ))
# return Div(props, children)
# return c
from django.forms.boundfield import BoundField
from django.forms.widgets import Widget, TextInput, CheckboxInput
from django.utils.functional import Promise
from django.utils.html import conditional_escape, format_html
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _
# from chp.components import *
from chp.store import (create_store, render_app)
from chp.mdc.components import *
"""
Boundfield has the following methods to render an HTML widget
using the template engine:
def __str__(self):
""" """Render this field as an HTML widget.""" """
if self.field.show_hidden_initial:
return self.as_widget() + self.as_hidden(only_initial=True)
return self.as_widget()
def as_widget(self, widget=None, attrs=None, only_initial=False):
""" """
Render the field by rendering the passed widget, adding any HTML
attributes passed as attrs. If a widget isn't specified, use the
field's default widget.
""" """
widget = widget or self.field.widget
if self.field.localize:
widget.is_localized = True
attrs = attrs or {}
attrs = self.build_widget_attrs(attrs, widget)
if self.auto_id and 'id' not in widget.attrs:
attrs.setdefault('id', self.html_initial_id if only_initial else self.auto_id)
return widget.render(
name=self.html_initial_name if only_initial else self.html_name,
value=self.value(),
attrs=attrs,
renderer=self.form.renderer,
)
def build_widget_attrs(self, attrs, widget=None):
widget = widget or self.field.widget
attrs = dict(attrs) # Copy attrs to avoid modifying the argument.
if widget.use_required_attribute(self.initial) and self.field.required and self.form.use_required_attribute:
attrs['required'] = True
if self.field.disabled:
attrs['disabled'] = True
return attrs
We need to use similar to get the attrs for 'required', etc.
Alternatively, create custom MdcWidgets and override the widget.render()?
Refactor functions here to classes to support code reuse.
"""
class ChpWidgetMixin:
chp_widget = None
def __init__(self, attrs=None, **kwargs):
self.label = kwargs.pop("label", None)
if attrs is not None:
attrs = attrs.copy()
super().__init__(attrs)
def render(self, name, value, attrs=None, renderer=None):
"""Build a context and render the widget as a component."""
context = self.get_context(name, value, attrs)
context['widget'].update(
{'label': self.label,
'id_for_label':
self.id_for_label(context['widget']['attrs']['id'])
})
# return self._render(self.template_name, context, renderer)
return self.chp_render(context)
def chp_render(self, context):
raise NotImplementedError
class MdcCheckboxInput(ChpWidgetMixin, CheckboxInput):
def chp_render(self, context):
ast_checkbox = Checkbox(
context['widget']['attrs']['checked'],
context['widget']['attrs']['id'],
context
)
children = [ast_checkbox,
MdcLabelWidget(context)
]
return FormField(children)
def MdcCheckbox(field):
# code taken from Boundfield.label_tag()
label_suffix = (field.field.label_suffix
if field.field.label_suffix is not None
else (field.form.label_suffix
if hasattr(field, "form") else ""))
contents = field.label
if label_suffix and contents and contents[-1] not in _(':?.!'):
label = format_html('{}{}', contents, label_suffix)
return field.as_widget(MdcCheckboxInput(label=label))
def MdcInput(field):
if field.mdc_type == "MDCDateField":
input_type = "date"
else:
input_type = "text"
ast = Input(input_type, field.auto_id)
# widget formatted value
value = field.field.widget.format_value(field.value())
if not (value == '' or value is None):
ast["props"].append(
cp("value", value)
)
# widget-level attrs
for (key, value) in field.field.widget.attrs.items():
ast["props"].append(
cp(key, value)
)
return ast
def DjLabel(field):
label = field.label
# cast gettext_lazy strings so they are recognised by AST renderer
if isinstance(label, Promise):
label = conditional_escape(label)
context = {
"input_type": field.field.widget.input_type,
"id_for_label": field.id_for_label,
"label": label,
}
return Label(label, context["id_for_label"], context)
def MdcLabelWidget(context):
label = context['widget']['label']
# render gettext_lazy strings so they are recognised by AST renderer
if isinstance(label, Promise):
label = str(label)
el_for = context['widget']['id_for_label']
el_context = {}
el_context["input_type"] = context['widget']['type']
return Label(label, el_for, el_context)
def MdcTextField(field):
if not hasattr(field, 'mdc_type'):
field.mdc_type = 'MDCTextField'
children = [
MdcInput(field),
DjLabel(field),
LineRipple(),
]
return InputField(field.field.widget.input_type, children)
def MdcDateField(field):
if not hasattr(field, 'mdc_type'):
field.mdc_type = 'MDCDateField'
return MdcTextField(field)
from django import forms
from django.urls import reverse
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _
from chp import chp
# from chp import chp
from chp.components import *
from chp.pyreact import (
context_middleware, inject_ids, render_element
)
from chp.store import (create_store, Inject_ast_into_DOM, render_app)
from chp.mdc.components import *
from .components import (
MdcCheckbox, MdcDateField, MdcTextField)
from .models import Post
class PostForm(forms.ModelForm):
def render(self):
import json
ast = FormSchema(store, json.dumps(store))
form = chp.pyreact.inject_ids(ast)
app = chp.Inject_ast_into_DOM(form, json.dumps(form))
html = chp.render_element(app, chp_build.context_middleware(ctx))
print(html)
print(form)
return mark_safe(html)
class Meta:
model = Post
exclude = []
fields = "__all__"
labels = {
'checkbox': _("This is my checkbox"),
'text': _("Input Label"),
'date': _("Type = date"),
}
def FormSchema(self, *args, **kwargs):
def render(self, *args, **kwargs):
form = Form([
Cell([
Div(
[cp("style", "display: flex;")],
[
MdcCheckbox(self["checkbox"]),
MdcTextField(self["text"]),
MdcDateField(self["date"]),
# MdcSelect(self["foreignkey"]),
],
),
])
],
action=reverse('blog:post_create'))
return form
return render(self)
def render(self):
ctx = {}
ast = self.FormSchema()
form = inject_ids(ast, context_middleware(ctx))
# app = Inject_ast_into_DOM(form, json.dumps(form))
# html = render_element(app, context_middleware(ctx))
html = render_element(form, context_middleware(ctx))
return mark_safe(html)
# Generated by Django 2.0.5 on 2018-07-13 00:34
# Generated by Django 2.1 on 2018-09-04 17:58
from django.conf import settings
from django.db import migrations, models
......@@ -18,12 +18,13 @@ class Migration(migrations.Migration):
name='Post',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=200)),
('publish_datetime', models.DateTimeField()),
('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
('checkbox', models.BooleanField()),
('text', models.CharField(max_length=200)),
('date', models.DateField()),
('foreignkey', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
options={
'ordering': ['title'],
'ordering': ['text'],
},
),
]
......@@ -2,12 +2,13 @@ from django.db import models
class Post(models.Model):
title = models.CharField(max_length=200)
author = models.ForeignKey('auth.User', models.CASCADE)
publish_datetime = models.DateTimeField()
checkbox = models.BooleanField()
text = models.CharField(max_length=200)
date = models.DateField()
foreignkey = models.ForeignKey('auth.User', models.CASCADE)
class Meta:
ordering = ['title']
ordering = ['text']
def __str__(self):
return self.title
return self.text
......@@ -3,12 +3,70 @@
<head>
<link rel="stylesheet" type="text/css" href="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.css" />
<script type="text/javascript" src="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.js"></script>
<script type="text/javascript" src="{% static "main.js" %}"></script>
<script type="text/javascript">
for(let key in chp_build) { window[key] = chp_build[key]};
</script>
</head>
<body>
<form action="{% url 'blog:post_create' %}" method="post">
{% csrf_token %}
{{ form }}
</form>
{{ form.render }}
<form action="{% url 'blog:post_create' %}" method="post">
<div class="mdc_layout_grid__cell">
<div style="display: flex;">
<div class="mdc-form-field mdc-form-field--align-end" data-mdc-auto-init="MDCFormField">
<div class="mdc-checkbox" data-mdc-auto-init="MDCCheckbox">
<input type="checkbox" class="mdc-checkbox__native-control"/>
<div class="mdc-checkbox__background">
</div>
</div>
<label for="my-checkbox">This is my checkbox</label>
</div>
<div class="mdc-text-field" data-mdc-auto-init="MDCTextField">
<input class="mdc-text-field__input" type="text" >
<label for="input" class="mdc-floating-label">Input Label</label>
<div class="mdc-line-ripple"></div>
</div>
<div class="mdc-text-field" data-mdc-auto-init="MDCTextField">
<input
class="mdc-text-field__input"
type="date"
>
<label
for="input"
class="mdc-floating-label"
>Type = date</label>
<div class="mdc-line-ripple"></div>
</div>
<div class="mdc-select" data-mdc-auto-init="MDCSelect">
<select class="mdc-select__native-control">
<option value="" disabled selected></option>
<option value="grains">
Bread, Cereal, Rice, and Pasta
</option>
<option value="vegetables">
Vegetables
</option>
<option value="fruit">
Fruit
</option>
</select>
<label class="mdc-floating-label">Pick a Food Group</label>
<div class="mdc-line-ripple"></div>
</div>
</div>
</div>
</form>
{# {{ form.render }} #}
<script type="text/javascript" src="{% static "output.js" %}"></script>
<script>window.mdc.autoInit();</script>
</body>
</html>
......@@ -7,3 +7,10 @@ from .models import Post
class PostCreateView(generic.CreateView):
form_class = PostForm
model = Post
def get_initial(self):
initial = super(PostCreateView, self).get_initial()
initial.update({'checkbox': True,
'text': 'Initial value',
})
return initial
......@@ -8,6 +8,9 @@
"start": "webpack-cli"
},
"dependencies": {
"autoprefixer": "^9.1.5",
"extract-text-webpack-plugin": "^4.0.0-beta.0",
"material-components-web": "^0.39.1",
"webpack": "^4.16.1",
"webpack-cli": "^3.1.0"
},
......
......@@ -15,6 +15,7 @@ INSTALLED_APPS = [
'chp.django', # management command
'chp.django.example.blog',
'chp.django.example.todos',
'crudlfap',
]
DATABASES = {
......@@ -26,7 +27,7 @@ DATABASES = {
STATIC_URL = '/static/'
BASE_DIR = os.path.dirname(__file__)
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "blog", "dist"),
BASE_DIR,
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
......
from chp.chp import *
from chp.components import *
from chp.store import (create_store, render_app)
def SubmitButton(name, on_click):
......@@ -29,6 +30,7 @@ def Input(value):
]
return ce('input', props, [])
def FormSchema(store_content, store_content_json):
store_name = "todoStore"
store_change_cb = [
......@@ -40,7 +42,6 @@ def FormSchema(store_content, store_content_json):
def render():
form = Form([
Cell([
Div(
[cp("style", "display: flex;")],
[
......@@ -49,11 +50,10 @@ def FormSchema(store_content, store_content_json):
],
),
Div(
[create_prop("style", "height: 5rem")],
[cp("style", "height: 5rem")],
"If you type <strong>foo</strong> in the textbox and unfocus, your secret message will appear !!"
),
Div([create_prop("id", "demo"), create_prop("style", "color: red" if store_content["name"] == "foo" else "color: green")], "what color am I ?"),
])
Div([cp("id", "demo"), cp("style", "color: red" if store_content["name"] == "foo" else "color: green")], "what color am I ?"),
])
todos = []
......@@ -68,5 +68,6 @@ def FormSchema(store_content, store_content_json):
Div([], todos),
],
)
return form
return render()
......@@ -5,10 +5,11 @@
<script type="text/javascript" src="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.js"></script>
<script type="text/javascript" src="{% static "todos.js" %}"></script>
<script type="text/javascript">
for(let key in chp_build) { window[key] = chp[key]};
// for(let key in chp_build) { window[key] = chp[key]};
</script>
</head>
<body>
{{ view.body }}
<script>window.mdc.autoInit();</script>
</body>
</html>
import json
from chp import chp
from django.utils.safestring import mark_safe
from django.views import generic
from chp.pyreact import (context_middleware, inject_ids, render_element)
from chp.store import Inject_ast_into_DOM
from .components import FormSchema
......@@ -15,9 +16,9 @@ class TodosView(generic.TemplateView):
is_checked = {
"name": "hello",
}
ctx={
ctx = {
"label": "Labelling:",
"password": "bar"
"password": "bar",
}
store = {
"name": "this is my first store !!",
......@@ -33,7 +34,7 @@ class TodosView(generic.TemplateView):
]
}
ast = FormSchema(store, json.dumps(store))
form = chp.inject_ids(ast)
app = chp.Inject_ast_into_DOM(form, json.dumps(form))
html = chp.render_element(app, chp.context_middleware(ctx))
form = inject_ids(ast)
app = Inject_ast_into_DOM(form, json.dumps(form))
html = render_element(app, context_middleware(ctx))
return mark_safe(html)
const autoprefixer = require('autoprefixer')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
var path = require('path')
/*
const { spawnSync } = require('child_process');
var fs = require('fs');
const child = spawnSync('chp',
['generate', '--entry-point', 'webpack.entry.py'], {maxBuffer: 20000*1024}
);
fs.writeFile('webpack_bundle.py', child.stdout, function(err) {
if(err) {
return console.log(err);
}
});
*/
const extractSass = new ExtractTextPlugin({
filename: 'main.css',
})
module.exports = {
mode: 'development',
entry: './webpack_entry.py',
devtool: 'source-map',
entry: './main.js',
output: {
filename: 'todos.js',
path: path.resolve(__dirname, 'todos/static')
filename: 'output.js',
path: path.resolve(__dirname)
},
// entry: './webpack_entry.py',
// output: {
// filename: 'todos.js',
// path: path.resolve(__dirname, 'todos/static')
// },
module: {
rules: [
{ test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: 'url-loader?limit=10000&mimetype=application/font-woff' },
{ test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: 'file-loader' },
{
test: /\.py$/,
loader: 'py-loader',
options: {
compiler: 'transcrypt'