I am trying to add markdown to my input text box for a flask project. I am following the Grinburg text book. In my forms.py I have :
from flask_pagedown.fields import PageDownField
from wtforms.fields.simple import HiddenField
class NewEntry(Form):
'''
A form for new entries
'''
title = TextAreaField("Title", validators=[Required()])
text = PageDownField("Text", validators=[Required()])
tags = TextAreaField("Tags", validators=[Required()])
srcLibEntries = HiddenField(label=None, id="srcLibArticles")
submit = SubmitField('Submit', id="new_entry_submit_button")
Over in my HTML, I have :
{% extends "layout.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block scripts %}
{{super()}}
{{pagedown.include_pagedown()}}
{% endblock %}
{% block body %}
<form method="post" role="form">
{{ wtf.form_field(form.title) }}
{{ wtf.form_field(form.text) }}
{{ wtf.form_field(form.tags) }}
{{ form.srcLibEntries }}
{{ wtf.form_field(form.submit) }}
</form>
All this unfurls at the browser to have the following code for the text input box :
<div class="form-group required"><label class="control-label" for="text">Text</label>
<div class="flask-pagedown"><textarea class="form-control flask-pagedown-input" id="flask-pagedown-text" name="text" required>fsdafds</textarea></div>
<div class="flask-pagedown-preview" id="flask-pagedown-text-preview"></div>
<script type="text/javascript">
f = function() {
if (typeof flask_pagedown_converter === "undefined")
flask_pagedown_converter = Markdown.getSanitizingConverter().makeHtml;
var textarea = document.getElementById("flask-pagedown-text");
var preview = document.getElementById("flask-pagedown-text-preview");
textarea.onkeyup = function() { preview.innerHTML = flask_pagedown_converter(textarea.value); }
textarea.onkeyup.call(textarea);
}
if (document.readyState === 'complete')
f();
else if (window.addEventListener)
window.addEventListener("load", f, false);
else if (window.attachEvent)
window.attachEvent("onload", f);
else
f();
</script>
</div>
I am getting an exception at the browser, namely, "Uncaught ReferenceError: Markdown is not defined" and it is referring to this line :
flask_pagedown_converter = Markdown.getSanitizingConverter().makeHtml;
I don't think I have to import any more markdown anywhere. What is going on here?
Edit 1:
I needed to add the following to my layout.css:
<script src="//cdnjs.cloudflare.com/ajax/libs/pagedown/1.0/Markdown.Converter.js"> </script>
<script src="//cdnjs.cloudflare.com/ajax/libs/pagedown/1.0/Markdown.Editor.js"> </script>
<script src="//cdnjs.cloudflare.com/ajax/libs/pagedown/1.0/Markdown.Sanitizer.js"> </script>
I needed to add the following to my layout.css:
<script src="//cdnjs.cloudflare.com/ajax/libs/pagedown/1.0/Markdown.Converter.js"> </script>
<script src="//cdnjs.cloudflare.com/ajax/libs/pagedown/1.0/Markdown.Editor.js"> </script>
<script src="//cdnjs.cloudflare.com/ajax/libs/pagedown/1.0/Markdown.Sanitizer.js"> </script>
Related
I try to minify partial HTML in which I minify some JS using terser (using a jsmin filter as showed in 11ty docs):
<!doctype html>
<html lang="fr"><head><meta charset="utf-8"><title></title></head>
{% set html %}
<body>
<div class="foo">
Bar
</div>
<script>{% set js %}
var foo = 'foo',
bar = 'bar';
{% endset %}{{ js | jsmin | safe }}</script>
{% endset %}
{{ html | htmlmin | safe }}
</body>
</html>
But since the terser process is asynchronous, it throws an error in 11ty (callback is not a function, and <script>[object Promise]</script> in the generated file).
Same problem if I try to minify all the HTML using an 11ty transform (as suggested in their docs: Minify HTML Output – and removing all the {% set html %} / {{ html | … }} tags): it throws some similar Promise errors (Having trouble writing template … Cannot read properties of undefined … at async Promise.all)
Problem solved if I move the script part outside of the Nunjucks set declaration:
<!doctype html>
<html lang="fr"><head><meta charset="utf-8"><title></title></head>
{% set html %}
<body>
<div class="foo">
Bar
</div>
{% endset %}
{{ html | htmlmin | safe }}
<script>{% set js %}
var foo = 'foo',
bar = 'bar';
{% endset %}{{ js | jsmin | safe }}</script>
</body>
</html>
But that's not what I want.
Trying to make terser synchronous seems to need some more npm packages so I'm hoping there's an easier way before trying it.
Edit: tried to use html-minifier-terser instead of html-minifier, with this code for the htmlmin filter:
const TerserHTML = require('html-minifier-terser');
…
eleventyConfig.addNunjucksAsyncFilter('htmlmin', async function(code, callback) {
try {
let minified = await TerserHTML.minify(code, {
removeComments: true,
collapseWhitespace: true
});
callback(null, minified);
} catch (err) {
console.error('Terser HTML error: ', err);
callback(null, code);
}
});
→ same issue
Picture 1 Picture 2 Picture 3 I am building a page in Django that first renders a blank page with a loading picture, and then calls an Ajax get function to one of my views. Once my Ajax get function succeeds, it is supposed to load one of my HTML files. I get a 404 error saying that the template cannot be found, but the template is in the same folder as my other file. Is my file path wrong?
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
</head>
{% extends "stocks_sites/base.html" %}
<!-- The loading image -->
{% block loader %}
<div id="loading">
<p>Loading</p>
</div>
<div id="articles">
</div>
<script>
// AJAX call when page has loaded
$(document).ready(function(){
$.ajax({
type: "GET",
url: "{% url 'stocks_sites:get_news_articles' %}",
success: function(response) {
const news_articles = response;
const posts = news_articles.posts;
const search = news_articles.search;
document.getElementById("loading").style.display = "none";
$("#articles").load("news_articles.html");
}
});
});
</script>
{% endblock loader %}
I have developed an app on Google App Engine in Python37 & Flask on the Standard Environment. I have the following file as the index.html for authentication. I have configured the Firebase authentication app to include Google, Email and Facebook authentication. However, the widget only shows Google and Email. None of the other implementations of the Firebase Authentication-UI returns the Token that can be verified in python main.py app.
index.html - I have the correct Firebase config values in my real html file
<!doctype html>
<html>
<head>
<title>Myapp</title>
<link rel="stylesheet" href="/static/bulma.min.css">
<script defer src="/static/all.js"></script>
<script src="https://www.gstatic.com/firebasejs/5.8.4/firebase.js"></script>
<script>
// Initialize Firebase
var config = {
apiKey: "<API_KEY>",
authDomain: "<PROJECT_ID>.firebaseapp.com",
databaseURL: "https://<DATABASE_NAME>.firebaseio.com",
projectId: "<PROJECT_ID>",
storageBucket: "<BUCKET>.appspot.com",
messagingSenderId: "<MESSAGING_SENDER_ID>"
};
firebase.initializeApp(config);
</script>
<script>
if (typeof firebase === 'undefined') {
const msg = "Please paste the Firebase initialization snippet into index.html. See https://console.firebase.google.com > Overview > Add Firebase to your web app.";
console.log(msg);
alert(msg);
}
</script>
<!-- [START gae_python37_auth_include_firebaseui] -->
<script src="https://cdn.firebase.com/libs/firebaseui/2.6.2/firebaseui.js"></script>
<link type="text/css" rel="stylesheet" href="https://cdn.firebase.com/libs/firebaseui/2.6.2/firebaseui.css">
<!-- [END gae_python37_auth_include_firebaseui] -->
<script src="{{ url_for('static', filename='script.js') }}"></script>
<link type="text/css" rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
<br><br><br>
<div class="title is-4 has-text-centered">
<div>
Welcome to Myapp
</div>
</div>
<div class="title is-5 has-text-centered">Myapp</div>
<!-- [START gae_python37_auth_firebase_html] -->
<div id="firebaseui-auth-container"></div>
<button id="sign-out" hidden=true>Sing out</button>
<div id="login-info" hidden=true>
</div>
<!-- [END gae_python37_auth_firebase_html] -->
<!-- Footer Section -->
</body>
</html>
main.py
id_token = request.cookies.get("token")
claims = google.oauth2.id_token.verify_firebase_token(
id_token, firebase_request_adapter)
See below the implementation I did as per this documentation that #Ajordat has referred to. I get a an empty id_token error - Illegal ID token provided: None. ID token must be a non-empty string
enter image description here
Here is the index.html page
<!doctype html>
<html>
<head>
<title>Datastore and Firebase Auth Example</title>
<script src="https://cdn.firebase.com/libs/firebaseui/3.5.2/firebaseui.js"></script>
<link type="text/css" rel="stylesheet" href="https://cdn.firebase.com/libs/firebaseui/3.5.2/firebaseui.css" />
<script src="https://www.gstatic.com/firebasejs/5.8.4/firebase.js"></script>
<script>
// Initialize Firebase
var config = {
apiKey: "<API_KEY>",
authDomain: "<PROJECT_ID>.firebaseapp.com",
databaseURL: "https://<DATABASE_NAME>.firebaseio.com",
projectId: "<PROJECT_ID>",
storageBucket: "<BUCKET>.appspot.com",
messagingSenderId: "<MESSAGING_SENDER_ID>"
};
firebase.initializeApp(config);
</script>
<script>
var uiConfig = {
callbacks: {
signInSuccessWithAuthResult: function(authResult, redirectUrl) {
// User successfully signed in.
// Return type determines whether we continue the redirect automatically
// or whether we leave that to developer to handle.
return true;
},
uiShown: function() {
// The widget is rendered.
// Hide the loader.
document.getElementById('loader').style.display = 'none';
}
},
// Will use popup for IDP Providers sign-in flow instead of the default, redirect.
signInFlow: 'popup',
signInSuccessUrl: '/',
signInOptions: [
// Leave the lines as is for the providers you want to offer your users.
firebase.auth.GoogleAuthProvider.PROVIDER_ID,
firebase.auth.FacebookAuthProvider.PROVIDER_ID,
firebase.auth.EmailAuthProvider.PROVIDER_ID
],
// Terms of service url.
tosUrl: '<your-tos-url>',
// Privacy policy url.
privacyPolicyUrl: '<your-privacy-policy-url>'
};
// Initialize the FirebaseUI Widget using Firebase.
var ui = new firebaseui.auth.AuthUI(firebase.auth());
// The start method will wait until the DOM is loaded.
ui.start('#firebaseui-auth-container', uiConfig);
</script>
</head>
<body>
<h1>Datastore and Firebase Auth Example</h1>
<!-- [START gae_python37_auth_firebase_html] -->
<div id="firebaseui-auth-container"></div>
<button id="sign-out" hidden=true>Sign Out</button>
<div id="login-info" hidden=true>
<h2>Login info:</h2>
{% if user_data %}
<dl>
<dt>Name</dt><dd>{{ user_data['name'] }}</dd>
<dt>Email</dt><dd>{{ user_data['email'] }}</dd>
<dt>Last 10 visits</dt><dd>
{% for time in times %}
<p>{{ time['timestamp'] }}</p>
{% endfor %} </dd>
</dl>
{% elif error_message %}
<p>Error: {{ error_message }}</p>
{% endif %}
</div>
User id :{{ uid }}
<br>
User: {{ user.email }}
<br>
Error: {{ error_message }}
<br><br><br>
{{ id_token }}
<!-- [END gae_python37_auth_firebase_html] -->
</body>
</html>
The main.py code for verifying the id_token
...
default_app = firebase_admin.initialize_app()
#app.route('/')
def root():
# Verify Firebase auth.
id_token = request.cookies.get("token")
error_message = ''
uid = None
user = None
# if id_token:
try:
decoded_token = auth.verify_id_token(id_token)
uid = decoded_token['uid']
user = auth.get_user(uid)
except ValueError as exc:
error_message = str(exc)
return render_template(
'index.html',
uid=uid, user=user, error_message = error_message)
The solution was to get the token from authResult.user and set it as a cookie so it can later be retrieved from the server. See the code attached:
signInSuccessWithAuthResult: function(authResult, redirectUrl) {
var user = authResult.user;
var credential = authResult.credential;
var isNewUser = authResult.additionalUserInfo.isNewUser;
var providerId = authResult.additionalUserInfo.providerId;
var operationType = authResult.operationType;
if (user) {
user.getIdToken().then(function (accessToken) {
console.log("token retrieved: " + accessToken);
document.cookie = "token=" + accessToken + "; samesite=Lax";
});
}
return true;
}
I am making a local page following this tutorial, and it implements a login using django and angular. But I can't get the button register to show anything. It just changes the directory to /register. I think it has to do with routing. I get no errors. And I don't know how to debug this thing anymore, so I've run out of options. This is my first 'website'.
Reason this isn't going smooth is because I did not get the starter project the tutorial came with. I wanted to learn how to implement this from scratch. This means my packages are newer (bootstrap, django, etc). Let me know if you need any more info, please. Thanks.
/templates/index.html
<!DOCTYPE html>
<html ng-app="hawk">
<head>
<title>Hawk</title>
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
</head>
<body>
{% include 'navbar.html' %}
<div class="container-fluid">
<div class="row">
<div class="col-xs-12 ng-view"></div>
</div>
</div>
{% include 'javascripts.html' %}
</body>
</html>
/static/javascripts/hawk.routes.js
(function () {
'use strict';
angular
.module('hawk.routes')
.config(config);
config.$inject = ['$routeProvider'];
function config($routeProvider) {
$routeProvider.when('/register', {
controller: 'RegisterController',
controllerAs: 'vm',
templateUrl: '/static/templates/authentication/register.html'
}).otherwise('/');
}
})();
/static/javascripts/authentication/controllers/register.controller.js
(function () {
'use strict';
angular
.module('hawk.authentication.controllers')
.controller('RegisterController', RegisterController);
RegisterController.$inject = ['$location', '$scope', 'Authentication'];
function RegisterController($location, $scope, Authentication) {
var vm = this;
console.log("\n\nregister\n\n");
vm.register = register;
function register() {
Authentication.register(vm.email, vm.password, vm.username);
}
}
})();
/static/javascripts/hawk.js
(function () {
'use strict';
angular
.module('hawk', [
'hawk.routes',
'hawk.authentication',
'hawk.config',
]);
angular
.module('hawk.routes', [require('angular-route')]);
angular
.module('hawk.config', []);
angular
.module('hawk')
.run(run);
run.$inject = ['$http'];
function run($http) {
$http.defaults.xsrfHeaderName = 'X-CSRFToken';
$http.defaults.xsrfCookieName = 'csrftoken';
}
})();
/templates/javascripts.html
{% load compress %} {% load staticfiles %} {% compress js %}
<script type="text/javascript" src="{% static '../node_modules/jquery/dist/jquery.js' %}"></script>
<script type="text/javascript" src="{% static '../node_modules/bootstrap/dist/js/bootstrap.js' %}"></script>
<script type="text/javascript" src="{% static '../node_modules/bootstrap-material-design/dist/js/material.js' %}"></script>
<script type="text/javascript" src="{% static '../node_modules/bootstrap-material-design/js/ripples.js' %}"></script>
<script type="text/javascript" src="{% static '../node_modules/underscore/underscore.js' %}"></script>
<script type="text/javascript" src="{% static '../node_modules/angular/angular.js' %}"></script>
<script type="text/javascript" src="{% static '../node_modules/angular-route/angular-route.js' %}"></script>
<script type="text/javascript" src="{% static '../node_modules/angular-cookies/angular-cookies.js' %}"></script>
<script type="text/javascript" src="{% static '../node_modules/ng-dialog/js/ngDialog.js' %}"></script>
<script type="text/javascript" src="{% static 'lib/snackbarjs/snackbar.min.js' %}"></script>
<script type="text/javascript" src="{% static 'javascripts/hawk.js' %}"></script>
<script type="text/javascript" src="{% static 'javascripts/hawk.config.js' %}"></script>
<script type="text/javascript" src="{% static 'javascripts/hawk.routes.js' %}"></script>
<script type="text/javascript" src="{% static 'javascripts/authentication/authentication.module.js' %}"></script>
<script type="text/javascript" src="{% static 'javascripts/authentication/services/authentication.service.js' %}"></script>
<script type="text/javascript" src="{% static 'javascripts/authentication/controllers/register.controller.js' %}"></script>
{% endcompress %}
/static/javascripts/authentication/services/authentication.service.js
(function () {
'use strict';
angular
.module('hawk.authentication.services')
.factory('Authentication', Authentication);
Authentication.$inject = ['$cookies', '$http'];
function Authentication($cookies, $http) {
var Authentication = {
register: register
};
return Authentication;
function register(email, password, username) {
return $http.post('/api/v1/accounts/', {
username: username,
password: password,
email: email
});
}
}
})();
/HawkProject/urls.py
from django.contrib import admin
from django.urls import path, re_path, include
from rest_framework_nested import routers
from authentication.views import AccountViewSet
from HawkProject.views import IndexView
router = routers.SimpleRouter()
router.register(r'accounts', AccountViewSet)
urlpatterns = [
path('admin/', admin.site.urls),
re_path(r'^api/v1/', include(router.urls)),
re_path(r'^.*$', IndexView.as_view(), name='index')
]
Although its not an answer to this question precisely but its an answer with a diff approach
The tutorial you have provided is too long and not included with video. I have worked on Django and AngularJS to create an ecommerce website. I'l suggest you not to mix Django and AngularJS as much as you can to avoid conflicts. That being said, I'll provide you what I implemented for User Registration in brief:
I kept User form separate from AngularJS forms because Django has its own way to handle User Management (Sign in,sign Up, session (using #login_required) etc).
I provided Register on the nav-bar. (Note: /signup is a url mapped in urls.py file)
<form name="regForm" class="form-signup" action="/sign_up/" method="post" role="form" onsubmit="return validateForm()">
{% csrf_token %}
{{form.errors.values.0}}
<div class="form-group reg-username" id="fname">
<div>
<input name="first_name" class="form-control input" size="20" placeholder="Enter First Name" type="text" required>
</div>
<p id="fname-error" class="help-block"></p>
</div>
<div class="form-group reg-username">
<div>
<input name="last_name" class="form-control input" size="20" placeholder="Enter Last Name" type="text" required>
</div>
</div>
<div class="form-group reg-email">
<div>
<input name="email" class="form-control input" placeholder="Enter Email" type="email" required>
</div>
</div>
<div class="form-group reg-password" id="pwd1">
<div>
<input name="password1" class="form-control input" placeholder="Password" type="password" required>
</div>
<p id="pwd-error1" class="help-block"></p>
</div>
<div class="form-group reg-password" id="pwd2">
<div>
<input name="password2" class="form-control input" placeholder="Confirm Password" type="password" required>
</div>
<p id="pwd-error2" class="help-block"></p>
</div>
<input name="submit" class="btn btn-block btn-lg btn-primary" value="REGISTER" type="submit">
</form>
Where url(r'^sign_up/', ('ecommerce.views.register_user')),
In the views.py
#sensitive_post_parameters()
#csrf_protect
#requires_csrf_token
def register_user(request):
args = {}
args.update(csrf(request))
if request.method == 'POST':
if not verify_google_recaptcha(request.POST):
return HttpResponse(get_status_response('Failure', 'Are you sure you are not a robot?'))
else:
logger.info('Recaptcha passed !!!')
form = RegistrationForm(request.POST)
msg = 'register'
args['form'] = form
if form.is_valid():
try:
# username = form.cleaned_data['username']
email_obj ={}
email_obj['email'] = form.cleaned_data['email']
email_obj['first_name'] = form.cleaned_data['first_name']
email_obj['last_name'] = form.cleaned_data['last_name']
salt = hashlib.sha1(str(random.random())).hexdigest()[:5]
activation_key = hashlib.sha1(salt + email_obj['email']).hexdigest()
email_obj['activation_link'] = ACTIVATION_LINK.format(activation_key)
template = get_template('RegistrationLink.html')
context = Context({'email': email_obj})
content = template.render(context)
emsg = EmailMultiAlternatives('Activation link for {0}'.format(DEFAULT_DOMAIN) , content, DEFAULT_FROM_EMAIL, to=[email_obj['email']])
emsg.attach_alternative(content, "text/html")
emsg.send()
form.save() # save user to database if form is valid
# Get user by username
user = SiteUser.objects.get(email=email_obj['email'])
# Create and save user profile
new_profile = UserProfile(user=user, activation_key=activation_key,
key_expires=settings.EXPIRATION_DAYS)
new_profile.save()
except Exception as e:
logger.exception(e)
return render_to_response('500.html')
# return HttpResponseRedirect('/register_success')
return render_to_response('confirm.html', {'msg': msg})
else:
args['form'] = RegistrationForm()
return render_to_response('userRegistration.html', args, context_instance=RequestContext(request))
Note: The code written in def register_user is core Djnago feature to handle user registration which I am exploiting. You can get these over internet
If you need to render any form such as Order address, then create a form of angular and simple pass the value to Django using $http (the /url_called from $http will be mapped in urls.py).
Make sure you are using {% verbatim %} and {% endverbatim %} whenever you are using {{ some_angular_variable }} because it contradicts withDjango Templatesyntax. Better to go forng-bind` as much as you can.
Ignore $locationProvider for now if you are in initial stage. You'll get some issues when using that with Django. I have a solution for that as well but for beginner, dont get into that. Try to integrate the plunkr code in your Django app and see if it's working. Start small, dont jump to complicated examples.
Check one basic example of ngRoute.
In case you get stuck, post another question and put the link in the comment so that I can help you in that as well
How to use "onload()" function in twig. I tried using windows.load and $(document).ready(function(){ ****** }) but the map does not to load. I got no errors using firebug
Here is the code with both and windows.load
https://gist.github.com/anonymous/f7d6954f172dbf67a6ac
for use without the jQuery library i recommand:
window.onload = function() {
alert('script works');
};
The best option using Twig is to using the javascript block:
...
{% block javascript %}
window.onload = function() {
alert('script works');
};
{% endblock %}
The javascript block will be inserted just before the /body tag.
Do this
<script type="text/javascript">
jQuery(document).ready(function () {
/*ALL YOUR CODE*/
});
</script>