├── .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 |
4 | {{ form.email.label }} 5 |
6 | {{ form.email(class_="p-2") }} 7 |
{{ errors.email | first }}
8 |
9 | {{ form.password.label }} 10 |
11 | {{ form.password(class_="p-2")}} 12 | {% for error in errors.password %} 13 |
{{ error }}
14 | {% endfor %} 15 |
16 | {{ form.password_confirm.label }} 17 |
18 | {{ form.password_confirm(class_="p-2") }} 19 |
{{ errors.password_confirm | first }}
20 |
21 |
22 | {{ form.submit(class_="p-2 border shadow") }} 23 |
24 |
25 |
26 | -------------------------------------------------------------------------------- /templates/meld/search.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 10 | 11 |

12 | {% if not state in states %} 13 | {% if states %} 14 |

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 | --------------------------------------------------------------------------------