From 91d1dcea5fce6ce8243f9e4089cc4b8fcb1a7f72 Mon Sep 17 00:00:00 2001 From: nypgand1 Date: Mon, 1 Feb 2016 18:24:34 +0800 Subject: [PATCH 1/3] add .gitignore --- .gitignore | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..7d440988 --- /dev/null +++ b/.gitignore @@ -0,0 +1,59 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ From 0c92c9680d69a1f01cdaea0c04376b5121187e78 Mon Sep 17 00:00:00 2001 From: nypgand1 Date: Mon, 1 Feb 2016 18:25:31 +0800 Subject: [PATCH 2/3] update BootstrapRenderer for logo-nav --- flask_bootstrap/nav.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/flask_bootstrap/nav.py b/flask_bootstrap/nav.py index 1f3ca5b2..a86a6350 100644 --- a/flask_bootstrap/nav.py +++ b/flask_bootstrap/nav.py @@ -15,7 +15,7 @@ def visit_Navbar(self, node): node_id = self.id or sha1(str(id(node)).encode()).hexdigest() root = tags.nav() if self.html5 else tags.div(role='navigation') - root['class'] = 'navbar navbar-default' + root['class'] = 'navbar navbar-inverse navbar-fixed-top' cont = root.add(tags.div(_class='container-fluid')) @@ -37,11 +37,18 @@ def visit_Navbar(self, node): # title may also have a 'get_url()' method, in which case we render # a brand-link if node.title is not None: + if hasattr(node.title, 'img_src'): + title = tags.img(src=node.title.img_src, + alt=getattr(node.title, 'img_alt', '')) + else: + title = node.title.text if hasattr(node.title, 'get_url'): - header.add(tags.a(node.title.text, _class='navbar-brand', - href=node.title.get_url())) + a = tags.a(_class='navbar-brand', + href=node.title.get_url()) else: - header.add(tags.span(node.title, _class='navbar-brand')) + a = tags.span(node.title, _class='navbar-brand') + a.add(title) + header.add(a) bar = cont.add(tags.div( _class='navbar-collapse collapse', From f7b2c7fdf8d995ed50564e9304901e8aa26b4a1c Mon Sep 17 00:00:00 2001 From: nypgand1 Date: Mon, 1 Feb 2016 18:26:06 +0800 Subject: [PATCH 3/3] add sample_app_logo --- sample_app_logo/__init__.py | 48 +++++++++++++++++ sample_app_logo/default_config.py | 7 +++ sample_app_logo/forms.py | 22 ++++++++ sample_app_logo/frontend.py | 68 +++++++++++++++++++++++++ sample_app_logo/nav.py | 7 +++ sample_app_logo/requirements.txt | 5 ++ sample_app_logo/static/html5shiv.min.js | 4 ++ sample_app_logo/static/logo-nav.css | 27 ++++++++++ sample_app_logo/static/respond.min.js | 6 +++ sample_app_logo/templates/index.html | 35 +++++++++++++ sample_app_logo/templates/logo-nav.html | 44 ++++++++++++++++ sample_app_logo/templates/signup.html | 15 ++++++ 12 files changed, 288 insertions(+) create mode 100644 sample_app_logo/__init__.py create mode 100644 sample_app_logo/default_config.py create mode 100644 sample_app_logo/forms.py create mode 100644 sample_app_logo/frontend.py create mode 100644 sample_app_logo/nav.py create mode 100644 sample_app_logo/requirements.txt create mode 100644 sample_app_logo/static/html5shiv.min.js create mode 100644 sample_app_logo/static/logo-nav.css create mode 100644 sample_app_logo/static/respond.min.js create mode 100644 sample_app_logo/templates/index.html create mode 100644 sample_app_logo/templates/logo-nav.html create mode 100644 sample_app_logo/templates/signup.html diff --git a/sample_app_logo/__init__.py b/sample_app_logo/__init__.py new file mode 100644 index 00000000..d34b8d8f --- /dev/null +++ b/sample_app_logo/__init__.py @@ -0,0 +1,48 @@ +# Welcome to the Flask-Bootstrap sample application. This will give you a +# guided tour around creating an application using Flask-Bootstrap. +# +# To run this application yourself, please install its requirements first: +# +# $ pip install -r sample_app/requirements.txt +# +# Then, you can actually run the application. +# +# $ flask --app=sample_app dev +# +# Afterwards, point your browser to http://localhost:5000, then check out the +# source. + +from flask import Flask +from flask_appconfig import AppConfig +from flask_bootstrap import Bootstrap + +from .frontend import frontend +from .nav import nav + + +def create_app(configfile=None): + # We are using the "Application Factory"-pattern here, which is described + # in detail inside the Flask docs: + # http://flask.pocoo.org/docs/patterns/appfactories/ + + app = Flask(__name__) + + # We use Flask-Appconfig here, but this is not a requirement + AppConfig(app) + + # Install our Bootstrap extension + Bootstrap(app) + + # Our application uses blueprints as well; these go well with the + # application factory. We already imported the blueprint, now we just need + # to register it: + app.register_blueprint(frontend) + + # Because we're security-conscious developers, we also hard-code disabling + # the CDN support (this might become a default in later versions): + app.config['BOOTSTRAP_SERVE_LOCAL'] = True + + # We initialize the navigation as well + nav.init_app(app) + + return app diff --git a/sample_app_logo/default_config.py b/sample_app_logo/default_config.py new file mode 100644 index 00000000..45fb299d --- /dev/null +++ b/sample_app_logo/default_config.py @@ -0,0 +1,7 @@ +# The default_config module automatically gets imported by Appconfig, if it +# exists. See https://pypi.python.org/pypi/flask-appconfig for details. + +# Note: Don't *ever* do this in a real app. A secret key should not have a +# default, rather the app should fail if it is missing. For the sample +# application, one is provided for convenience. +SECRET_KEY = 'devkey' diff --git a/sample_app_logo/forms.py b/sample_app_logo/forms.py new file mode 100644 index 00000000..059ff9e8 --- /dev/null +++ b/sample_app_logo/forms.py @@ -0,0 +1,22 @@ +from flask_wtf import Form +from wtforms.fields import * +from wtforms.validators import Required, Email + + +class SignupForm(Form): + name = TextField(u'Your name', validators=[Required()]) + password = TextField(u'Your favorite password', validators=[Required()]) + email = TextField(u'Your email address', validators=[Email()]) + birthday = DateField(u'Your birthday') + + a_float = FloatField(u'A floating point number') + a_decimal = DecimalField(u'Another floating point number') + a_integer = IntegerField(u'An integer') + + now = DateTimeField(u'Current time', + description='...for no particular reason') + sample_file = FileField(u'Your favorite file') + eula = BooleanField(u'I did not read the terms and conditions', + validators=[Required('You must agree to not agree!')]) + + submit = SubmitField(u'Signup') diff --git a/sample_app_logo/frontend.py b/sample_app_logo/frontend.py new file mode 100644 index 00000000..c9dec1c6 --- /dev/null +++ b/sample_app_logo/frontend.py @@ -0,0 +1,68 @@ +# This contains our frontend; since it is a bit messy to use the @app.route +# decorator style when using application factories, all of our routes are +# inside blueprints. This is the front-facing blueprint. +# +# You can find out more about blueprints at +# http://flask.pocoo.org/docs/blueprints/ + +from flask import Blueprint, render_template, flash, redirect, url_for +from flask_bootstrap import __version__ as FLASK_BOOTSTRAP_VERSION +from flask_nav.elements import Navbar, View, ViewImg, Subgroup, Link, Text, Separator +from markupsafe import escape + +from .forms import SignupForm +from .nav import nav + +frontend = Blueprint('frontend', __name__) + +# We're adding a navbar as well through flask-navbar. In our example, the +# navbar has an usual amount of Link-Elements, more commonly you will have a +# lot more View instances. +nav.register_element('frontend_top', Navbar( + ViewImg('http://placehold.it/150x50&text=Logo', 'Flask-Bootstrap', + '.index'), + View('Home', '.index'), + View('Forms Example', '.example_form'), + View('Debug-Info', 'debug.debug_root'), + Subgroup( + 'Docs', + Link('Flask-Bootstrap', 'http://pythonhosted.org/Flask-Bootstrap'), + Link('Flask-AppConfig', 'https://github.com/mbr/flask-appconfig'), + Link('Flask-Debug', 'https://github.com/mbr/flask-debug'), + Separator(), + Text('Bootstrap'), + Link('Getting started', 'http://getbootstrap.com/getting-started/'), + Link('CSS', 'http://getbootstrap.com/css/'), + Link('Components', 'http://getbootstrap.com/components/'), + Link('Javascript', 'http://getbootstrap.com/javascript/'), + Link('Customize', 'http://getbootstrap.com/customize/'), + ), + Text('Using Flask-Bootstrap {}'.format(FLASK_BOOTSTRAP_VERSION)), +)) + + +# Our index-page just shows a quick explanation. Check out the template +# "templates/index.html" documentation for more details. +@frontend.route('/') +def index(): + return render_template('index.html') + + +# Shows a long signup form, demonstrating form rendering. +@frontend.route('/example-form/', methods=('GET', 'POST')) +def example_form(): + form = SignupForm() + + if form.validate_on_submit(): + # We don't have anything fancy in our application, so we are just + # flashing a message when a user completes the form successfully. + # + # Note that the default flashed messages rendering allows HTML, so + # we need to escape things if we input user values: + flash('Hello, {}. You have successfully signed up' + .format(escape(form.name.data))) + + # In a real application, you may wish to avoid this tedious redirect. + return redirect(url_for('.index')) + + return render_template('signup.html', form=form) diff --git a/sample_app_logo/nav.py b/sample_app_logo/nav.py new file mode 100644 index 00000000..9f055b44 --- /dev/null +++ b/sample_app_logo/nav.py @@ -0,0 +1,7 @@ +from flask_nav import Nav + +# To keep things clean, we keep our Flask-Nav instance in here. We will define +# frontend-specific navbars in the respective frontend, but it is also possible +# to put share navigational items in here. + +nav = Nav() diff --git a/sample_app_logo/requirements.txt b/sample_app_logo/requirements.txt new file mode 100644 index 00000000..61591e01 --- /dev/null +++ b/sample_app_logo/requirements.txt @@ -0,0 +1,5 @@ +flask-appconfig>=0.10 +flask-bootstrap +flask-nav +flask-debug +flask-wtf diff --git a/sample_app_logo/static/html5shiv.min.js b/sample_app_logo/static/html5shiv.min.js new file mode 100644 index 00000000..92f741f4 --- /dev/null +++ b/sample_app_logo/static/html5shiv.min.js @@ -0,0 +1,4 @@ +/** +* @preserve HTML5 Shiv 3.7.3-pre | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed +*/ +!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3-pre",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/sample_app_logo/static/logo-nav.css b/sample_app_logo/static/logo-nav.css new file mode 100644 index 00000000..5fe7e7ae --- /dev/null +++ b/sample_app_logo/static/logo-nav.css @@ -0,0 +1,27 @@ +/*! + * Start Bootstrap - Logo Nav HTML Template (http://startbootstrap.com) + * Code licensed under the Apache License v2.0. + * For details, see http://www.apache.org/licenses/LICENSE-2.0. + */ + +body { + padding-top: 70px; /* Required padding for .navbar-fixed-top. Change if height of navigation changes. */ +} + +.navbar-fixed-top .nav { + padding: 15px 0; +} + +.navbar-fixed-top .navbar-brand { + padding: 0 15px; +} + +@media(min-width:768px) { + body { + padding-top: 100px; /* Required padding for .navbar-fixed-top. Change if height of navigation changes. */ + } + + .navbar-fixed-top .navbar-brand { + padding: 15px 0; + } +} \ No newline at end of file diff --git a/sample_app_logo/static/respond.min.js b/sample_app_logo/static/respond.min.js new file mode 100644 index 00000000..e8d6207f --- /dev/null +++ b/sample_app_logo/static/respond.min.js @@ -0,0 +1,6 @@ +/*! Respond.js v1.4.2: min/max-width media query polyfill + * Copyright 2014 Scott Jehl + * Licensed under MIT + * http://j.mp/respondjs */ + +!function(a){"use strict";a.matchMedia=a.matchMedia||function(a){var b,c=a.documentElement,d=c.firstElementChild||c.firstChild,e=a.createElement("body"),f=a.createElement("div");return f.id="mq-test-1",f.style.cssText="position:absolute;top:-100em",e.style.background="none",e.appendChild(f),function(a){return f.innerHTML='­',c.insertBefore(e,d),b=42===f.offsetWidth,c.removeChild(e),{matches:b,media:a}}}(a.document)}(this),function(a){"use strict";function b(){v(!0)}var c={};a.respond=c,c.update=function(){};var d=[],e=function(){var b=!1;try{b=new a.XMLHttpRequest}catch(c){b=new a.ActiveXObject("Microsoft.XMLHTTP")}return function(){return b}}(),f=function(a,b){var c=e();c&&(c.open("GET",a,!0),c.onreadystatechange=function(){4!==c.readyState||200!==c.status&&304!==c.status||b(c.responseText)},4!==c.readyState&&c.send(null))},g=function(a){return a.replace(c.regex.minmaxwh,"").match(c.regex.other)};if(c.ajax=f,c.queue=d,c.unsupportedmq=g,c.regex={media:/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,keyframes:/@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,comments:/\/\*[^*]*\*+([^/][^*]*\*+)*\//gi,urls:/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,findStyles:/@media *([^\{]+)\{([\S\s]+?)$/,only:/(only\s+)?([a-zA-Z]+)\s?/,minw:/\(\s*min\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,maxw:/\(\s*max\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,minmaxwh:/\(\s*m(in|ax)\-(height|width)\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/gi,other:/\([^\)]*\)/g},c.mediaQueriesSupported=a.matchMedia&&null!==a.matchMedia("only all")&&a.matchMedia("only all").matches,!c.mediaQueriesSupported){var h,i,j,k=a.document,l=k.documentElement,m=[],n=[],o=[],p={},q=30,r=k.getElementsByTagName("head")[0]||l,s=k.getElementsByTagName("base")[0],t=r.getElementsByTagName("link"),u=function(){var a,b=k.createElement("div"),c=k.body,d=l.style.fontSize,e=c&&c.style.fontSize,f=!1;return b.style.cssText="position:absolute;font-size:1em;width:1em",c||(c=f=k.createElement("body"),c.style.background="none"),l.style.fontSize="100%",c.style.fontSize="100%",c.appendChild(b),f&&l.insertBefore(c,l.firstChild),a=b.offsetWidth,f?l.removeChild(c):c.removeChild(b),l.style.fontSize=d,e&&(c.style.fontSize=e),a=j=parseFloat(a)},v=function(b){var c="clientWidth",d=l[c],e="CSS1Compat"===k.compatMode&&d||k.body[c]||d,f={},g=t[t.length-1],p=(new Date).getTime();if(b&&h&&q>p-h)return a.clearTimeout(i),i=a.setTimeout(v,q),void 0;h=p;for(var s in m)if(m.hasOwnProperty(s)){var w=m[s],x=w.minw,y=w.maxw,z=null===x,A=null===y,B="em";x&&(x=parseFloat(x)*(x.indexOf(B)>-1?j||u():1)),y&&(y=parseFloat(y)*(y.indexOf(B)>-1?j||u():1)),w.hasquery&&(z&&A||!(z||e>=x)||!(A||y>=e))||(f[w.media]||(f[w.media]=[]),f[w.media].push(n[w.rules]))}for(var C in o)o.hasOwnProperty(C)&&o[C]&&o[C].parentNode===r&&r.removeChild(o[C]);o.length=0;for(var D in f)if(f.hasOwnProperty(D)){var E=k.createElement("style"),F=f[D].join("\n");E.type="text/css",E.media=D,r.insertBefore(E,g.nextSibling),E.styleSheet?E.styleSheet.cssText=F:E.appendChild(k.createTextNode(F)),o.push(E)}},w=function(a,b,d){var e=a.replace(c.regex.comments,"").replace(c.regex.keyframes,"").match(c.regex.media),f=e&&e.length||0;b=b.substring(0,b.lastIndexOf("/"));var h=function(a){return a.replace(c.regex.urls,"$1"+b+"$2$3")},i=!f&&d;b.length&&(b+="/"),i&&(f=1);for(var j=0;f>j;j++){var k,l,o,p;i?(k=d,n.push(h(a))):(k=e[j].match(c.regex.findStyles)&&RegExp.$1,n.push(RegExp.$2&&h(RegExp.$2))),o=k.split(","),p=o.length;for(var q=0;p>q;q++)l=o[q],g(l)||m.push({media:l.split("(")[0].match(c.regex.only)&&RegExp.$2||"all",rules:n.length-1,hasquery:l.indexOf("(")>-1,minw:l.match(c.regex.minw)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:l.match(c.regex.maxw)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}v()},x=function(){if(d.length){var b=d.shift();f(b.href,function(c){w(c,b.href,b.media),p[b.href]=!0,a.setTimeout(function(){x()},0)})}},y=function(){for(var b=0;b + {%- with messages = get_flashed_messages(with_categories=True) %} + {%- if messages %} +
+
+ {{utils.flashed_messages(messages)}} +
+
+ {%- endif %} + {%- endwith %} +
+

Welcome to Flask-Bootstrap

+

This example application demonstrates some (but not all!) of the + features of + Flask-Bootstrap.

+

+ Show docs +

+
+{%- endblock %} diff --git a/sample_app_logo/templates/logo-nav.html b/sample_app_logo/templates/logo-nav.html new file mode 100644 index 00000000..e0c2e1ca --- /dev/null +++ b/sample_app_logo/templates/logo-nav.html @@ -0,0 +1,44 @@ +{# ``base.html`` is the template all our other templates derive from. While + Flask-Bootstrap ships with its own base, it is good form to create a custom + one for our app, as it allows customizing some aspects. + + Deriving from bootstap/base.html gives us a basic page scaffoling. + + You can find additional information about template inheritance at + + http://jinja.pocoo.org/docs/templates/#template-inheritance +#} +{%- extends "bootstrap/base.html" %} + +{# We also set a default title, usually because we might forget to set one. + In our sample app, we will most likely just opt not to change it #} +{% block title %}Sample App for Flask-Bootstrap{% endblock %} + +{# While we are at it, we also enable fixes for legacy browsers. First we + import the necessary macros: #} +{% import "bootstrap/fixes.html" as fixes %} + +{# Then, inside the head block, we apply these. To not replace the header, + ``super()`` is used: #} +{% block head %} +{{super()}} + +{#- Docs: http://pythonhosted.org/Flask-Bootstrap/macros.html#fixes + The sample application already contains the required static files. #} +{{fixes.ie8()}} +{%- endblock %} + +{# Adding our own CSS files is also done here. Check the documentation at + http://pythonhosted.org/Flask-Bootstrap/basic-usage.html#available-blocks + for an overview. #} +{% block styles -%} + {{super()}} {# do not forget to call super or Bootstrap's own stylesheets + will disappear! #} + +{% endblock %} + +{# Finally, round things out with navigation #} +{% block navbar %} +{{nav.frontend_top.render()}} +{% endblock %} diff --git a/sample_app_logo/templates/signup.html b/sample_app_logo/templates/signup.html new file mode 100644 index 00000000..d33d9dc6 --- /dev/null +++ b/sample_app_logo/templates/signup.html @@ -0,0 +1,15 @@ +{% import "bootstrap/wtf.html" as wtf %} + +{%- extends "logo-nav.html" %} + + +{% block content %} +
+
+

Signup for our awesome service

+

Note: Your data isn't going anywhere.

+
+
+ {{form|render_form()}} +
+{%- endblock %}