├── .gitignore
├── requirements.txt
├── meld
└── components
│ ├── person.py
│ ├── register.py
│ ├── counter.py
│ └── search.py
├── templates
├── register_page.html
├── meld
│ ├── counter.html
│ ├── person.html
│ ├── register.html
│ └── search.html
└── base.html
├── README.md
├── app.py
└── forms.py
/.gitignore:
--------------------------------------------------------------------------------
1 | venv
2 | *.pyc
3 | *.egg-info
4 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | Flask>=0.9
2 | Flask-Meld==0.4.9
3 | Flask-WTF==0.14.3
4 | email-validator==1.1.2
5 |
--------------------------------------------------------------------------------
/meld/components/person.py:
--------------------------------------------------------------------------------
1 | from flask_meld.component import Component
2 |
3 |
4 | class Person(Component):
5 | first_name = ""
6 | last_name = ""
7 |
--------------------------------------------------------------------------------
/templates/register_page.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 |
5 |
Flask-Meld
6 | {% meld 'register' %}
7 |
8 |
9 | {% endblock %}
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Install requirements
2 |
3 | ```sh
4 | pip install -r requirements.txt
5 | ```
6 |
7 | # Run the application
8 |
9 | ```sh
10 | export FLASK_ENV=development
11 | python app.py
12 | ```
13 | visit `localhost:5000` in your browser
14 |
--------------------------------------------------------------------------------
/meld/components/register.py:
--------------------------------------------------------------------------------
1 | from flask_meld import Component
2 | from forms import RegistrationForm
3 |
4 |
5 | class Register(Component):
6 | form = RegistrationForm()
7 |
8 | def updated(self, field):
9 | self.validate(field)
10 |
--------------------------------------------------------------------------------
/meld/components/counter.py:
--------------------------------------------------------------------------------
1 | from flask_meld.component import Component
2 |
3 |
4 | class Counter(Component):
5 | count = 0
6 |
7 | def add(self):
8 | self.count = int(self.count) + 1
9 |
10 | def subtract(self):
11 | self.count = int(self.count) - 1
12 |
--------------------------------------------------------------------------------
/templates/meld/counter.html:
--------------------------------------------------------------------------------
1 |
2 |
Counter component
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/templates/meld/person.html:
--------------------------------------------------------------------------------
1 |
2 |
Simple databinding
3 |
4 |
5 | {% if first_name or last_name %}
6 |
Hello {{first_name}}{% if last_name %} {{last_name}}{% endif %}!
7 | {% endif %}
8 |
9 |
--------------------------------------------------------------------------------
/app.py:
--------------------------------------------------------------------------------
1 | from flask import Flask, render_template, redirect, url_for, request
2 | from flask_meld import Meld
3 | from forms import RegistrationForm
4 |
5 | app = Flask(__name__)
6 | app.config['SECRET_KEY'] = 'big!secret'
7 | Meld(app)
8 | socketio = app.socketio
9 |
10 |
11 | @app.route('/')
12 | def index():
13 | return render_template("base.html")
14 |
15 |
16 | @app.route('/register', methods=['GET', 'POST'])
17 | def register():
18 | form = RegistrationForm()
19 | if form.validate_on_submit():
20 | return redirect(url_for(request.url))
21 | return render_template("register_page.html")
22 |
23 |
24 | if __name__ == '__main__':
25 | socketio.run(app)
26 |
--------------------------------------------------------------------------------
/templates/meld/register.html:
--------------------------------------------------------------------------------
1 |
2 |
Registration Form
3 |
25 |
26 |
--------------------------------------------------------------------------------
/templates/meld/search.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
12 | {% if not state in states %}
13 | {% if states %}
14 |
15 | {% for s in states %}
16 | - {{ s }}
20 | {% endfor %}
21 |
22 | {% endif %}
23 | {% endif %}
24 |
25 |
26 |
--------------------------------------------------------------------------------
/templates/base.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Meld
5 |
6 |
7 |
8 |
9 |
10 | {% block head_scripts %}
11 | {% endblock %}
12 |
13 |
14 |
15 | {% meld_scripts %}
16 |
17 | {% block content %}
18 |
19 |
Flask-Meld Example
20 | {% meld 'person' %}
21 | {% meld 'counter' %}
22 | {% meld 'search' %}
23 |
24 |
25 | {% endblock %}
26 |
27 |
28 | {% block page_scripts %}
29 | {% endblock %}
30 |
31 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/forms.py:
--------------------------------------------------------------------------------
1 | from flask_wtf import FlaskForm
2 | from wtforms import (
3 | StringField,
4 | PasswordField,
5 | SubmitField,
6 | IntegerField,
7 | FormField,
8 | FieldList,
9 | Form,
10 | )
11 | from wtforms.validators import DataRequired, Email, EqualTo, Optional, Length, Regexp
12 |
13 |
14 | class RegistrationForm(FlaskForm):
15 | email = StringField("Email", validators=[DataRequired(), Email()])
16 | password = PasswordField(
17 | "Password",
18 | validators=[
19 | DataRequired(),
20 | Length(min=8, message="Password be at least 8 characters"),
21 | Regexp("^(?=.*[a-z])", message="Password must have a lowercase character"),
22 | Regexp("^(?=.*[A-Z])", message="Password must have an uppercase character"),
23 | Regexp("^(?=.*\\d)", message="Password must contain a number"),
24 | Regexp(
25 | "(?=.*[@$!%*#?&])", message="Password must contain a special character"
26 | ),
27 | ],
28 | )
29 | password_confirm = PasswordField(
30 | "Confirm Password",
31 | validators=[
32 | DataRequired(),
33 | EqualTo("password", message="Passwords must match"),
34 | ],
35 | )
36 | submit = SubmitField("Submit")
37 |
38 |
39 | class ProductForm(Form):
40 | title = StringField("Title")
41 | price = IntegerField("Price", validators=[Optional()])
42 |
43 |
44 | class InventoryForm(FlaskForm):
45 | category_name = StringField("Category Name")
46 | products = FieldList(FormField(ProductForm), min_entries=4, max_entries=8)
47 |
--------------------------------------------------------------------------------
/meld/components/search.py:
--------------------------------------------------------------------------------
1 | from flask_meld.component import Component
2 |
3 |
4 | class Search(Component):
5 | state = ""
6 | selected = 1
7 |
8 | _ALL_STATES = (
9 | "Alabama",
10 | "Alaska",
11 | "Arizona",
12 | "Arkansas",
13 | "California",
14 | "Colorado",
15 | "Connecticut",
16 | "Delaware",
17 | "Florida",
18 | "Georgia",
19 | "Hawaii",
20 | "Idaho",
21 | "Illinois",
22 | "Indiana",
23 | "Iowa",
24 | "Kansas",
25 | "Kentucky",
26 | "Louisiana",
27 | "Maine",
28 | "Maryland",
29 | "Massachusetts",
30 | "Michigan",
31 | "Minnesota",
32 | "Mississippi",
33 | "Missouri",
34 | "Montana",
35 | "Nebraska",
36 | "Nevada",
37 | "New Hampshire",
38 | "New Jersey",
39 | "New Mexico",
40 | "New York",
41 | "North Carolina",
42 | "North Dakota",
43 | "Ohio",
44 | "Oklahoma",
45 | "Oregon",
46 | "Pennsylvania",
47 | "Rhode Island",
48 | "South Carolina",
49 | "South Dakota",
50 | "Tennessee",
51 | "Texas",
52 | "Utah",
53 | "Vermont",
54 | "Virginia",
55 | "Washington",
56 | "West Virginia",
57 | "Wisconsin",
58 | "Wyoming",
59 | )
60 |
61 | def clear_states(self):
62 | self.state = ""
63 |
64 | def select(self, value):
65 | self.state = str(value)
66 |
67 | def select_by_index(self, value):
68 | self.state = self.states[int(value)-1]
69 |
70 | def select_next(self):
71 | if self.selected < len(self.states):
72 | self.selected += 1
73 |
74 | def select_previous(self):
75 | if self.selected > 1:
76 | self.selected -= 1
77 |
78 | @property
79 | def states(self):
80 | if not self.state:
81 | return []
82 |
83 | filtered_states = [s for s in self._ALL_STATES if s.lower().startswith(self.state.lower())]
84 | return filtered_states
85 |
--------------------------------------------------------------------------------