[code type=xml]
…
https://stackoverflow.com/questions/42986306/jasperreports-embedding-chart-as-svg-into-html-report
Emmet is a plugin for many popular text editors which greatly improves HTML & CSS workflow:
https://emmet.io
Nota do livro: 8.
Descrição rápida:
O HTML5 não constitui apenas algumas tags e recursos novos adicionados a um velho padrão – ele é a base da Web moderna, alavancando seus serviços interativos, UI de página única, jogos interativos e aplicativos empresariais complexos. Com o suporte ao desenvolvimento de aplicativos móveis baseados em padrões, recursos poderosos como o armazenamento local e WebSockets, ótimas APIs de áudio e vídeo e novas opções de layout com o uso de CSS3, SVG e Canvas, o HTML5 entrou em sua fase áurea.
O livro HTML5 em Ação fornece uma introdução completa ao desenvolvimento web com o uso de HTML5. Ele examina a especificação HTML5 por meio de códigos e exemplos do mundo real. Também faz jus ao termo “em Ação” disponibilizando o guia útil e prático necessário para a construção segura dos aplicativos e sites que você (e seus clientes) espera há anos.
Qual o conteúdo?
Novos elementos semânticos e tipos de entrada de formulário
Design de aplicativo de página única
Criação de elementos gráficos interativos
Aplicativos web móveis
Este livro é dedicado aos novos recursos HTML5 e supõe que você esteja familiarizado com HTML padrão.
Nota do livro: 6.
https://devblast.com/b/cors-with-angular-js-and-sinatra
UPDATE: I’ve created a follow-up article that shows PUT and DELETE calls.
Today, I’m gonna talk about something that always caused me a lot of pain, everytime I had to deal with it : Same-origin policy. This thing is simply awful if you have to make HTTP requests from Javascript.
To counter that, you can use JSONP. But only to make GET requests. If you need more than that (POST, PUT, DELETE), you will have to use Cross-Origin Resource Sharing and that’s what I am going to explain in this post. To do this, I will use Angular.js and Sinatra. Let’s get started, shall we ?
To follow this tutorial, you will need a version of Ruby and the Sinatra gem installed. You will also need a webserver, if you don’t have any check my post about SimpleHTTPServer.
So here is the basic code nothing fancy, a very very simple index.html, an angular module called MyApp completly empty and a Sinatra app with the basic route /hi coming from the documentation.
<!doctype html>
<html ng-app="myApp">
<head>
<title>CORS App</title>
</head>
<body>
Cross-Origin Resource Sharing
<script src="http://code.angularjs.org/1.1.5/angular.min.js"></script>
<script src="app.js"></script>
</body>
</html>
var app = angular.module('myApp', []);
require 'sinatra'
get '/hi' do
"Hello World!"
end
Just create three files : index.html, app.js and server.rb and Copy/Paste the corresponding code in each file.
You can run the Sinatra server with ruby server.rb
and you can use any webserver to access index.html at http://localhost:9000. Indeed, CORS calls won’t work if you use the file url, you need a real domain.
Let’s get started by configuring the Sinatra app (don’t forget to restart Sinatra server) :
require 'sinatra'
require 'json'
before do
content_type :json
end
set :protection, false
get '/movie' do
{ result: "Monster University" }.to_json
end
post '/movie' do
{ result: params[:movie] }.to_json
end
Okay, we are ready to go. If you access http://localhost:4567/movie from your browser, you should be able to see the last movie I saw. So let’s make our first javascript HTTP GET call.
<!doctype html>
<html ng-app="myApp">
<head>
<title>CORS App</title>
</head>
<body ng-controller="MainCtrl">
Cross-Origin Resource Sharing<br/>
<button ng-click="get()">GET</button>
Result : {{result}}
<script src="http://code.angularjs.org/1.1.5/angular.min.js"></script>
<script src="app.js"></script>
</body>
</html>
var app = angular.module('myApp', []);
app.controller('MainCtrl', function($scope, $http) {
$scope.get = function() {
$http.get("http://localhost:4567/movie").success(function(result) {
console.log("Success", result);
$scope.result = result;
}).error(function() {
console.log("error");
});
};
});
Open it in your browser. You should see this beautiful red line saying that you cannot access this resouce due to the Same-origin policy.
XMLHttpRequest cannot load http://localhost:4567/movie. Origin http://localhost:8000 is not allowed by Access-Control-Allow-Origin.
Time to fix that with Cross-origin Resource Sharing !
var app = angular.module('myApp', []);
app.config(function($httpProvider) {
//Enable cross domain calls
$httpProvider.defaults.useXDomain = true;
//Remove the header used to identify ajax call that would prevent CORS from working
delete $httpProvider.defaults.headers.common['X-Requested-With'];
});
app.controller('MainCtrl', function($scope, $http) {
$scope.get = function() {
$http.get("http://localhost:4567/movie").success(function(result) {
console.log("Success", result);
$scope.result = result;
}).error(function() {
console.log("error");
});
};
});
require 'sinatra'
require 'json'
before do
content_type :json
headers 'Access-Control-Allow-Origin' => '*',
'Access-Control-Allow-Methods' => ['OPTIONS', 'GET', 'POST']
end
set :protection, false
options '/movie' do
200
end
get '/movie' do
{ result: "Monster University" }.to_json
end
post '/movie' do
{ result: params[:movie] }.to_json
end
Restart Sinatra server and tadaaaa ! Now it’s working \o/ So what did we do ?
Well, first we told the $http module that we were going to send requests to another domain. We also removed the header used by the browser/server to identify our call as XmlHTTPRequest. Then, we enabled CORS on the server by specifying the available HTTP methods and the allowed origins (in our case, any origin *).
You probably noticed that we added a new route on our server :
options '/movie' do
This is part of the Cross-Origin Resource Sharing specification. Before sending a request to another domain, a call with the HTTP method OPTIONS will be fired. The response to this call will determine if CORS is available or not. This response must contain the allowed origins and the available HTTP methods
In a production environment, you should not accept any origin of course, you should specify the allowed domain names like this :
headers 'Access-Control-Allow-Origin' => 'http://localhost:9000, http://localhost:8000'
You should also keep the default Sinatra protection enabled. However, you may have to disable the http origin security to make CORS calls work with Sinatra.
set :protection, except: :http_origin
Unfortunately, we are not done yet. Let’s add a post call and see it miserably fail… :
<!doctype html>
<html ng-app="myApp">
<head>
<title>CORS App</title>
</head>
<body ng-controller="MainCtrl">
Cross-Origin Resource Sharing<br/>
<button ng-click="get()">GET</button>
Result : {{resultGet}}
<br/>
<input ng-model="movie"/><button ng-click="post(movie)">POST</button>
Result : {{resultPost}}
<script src="http://code.angularjs.org/1.1.5/angular.min.js"></script>
<script src="app.js"></script>
</body>
</html>
var app = angular.module('myApp', []);
app.config(function($httpProvider) {
//Enable cross domain calls
$httpProvider.defaults.useXDomain = true;
//Remove the header containing XMLHttpRequest used to identify ajax call
//that would prevent CORS from working
delete $httpProvider.defaults.headers.common['X-Requested-With'];
});
app.controller('MainCtrl', function($scope, $http) {
$scope.get = function() {
$http.get("http://localhost:4567/movie").success(function(result) {
console.log("Success", result);
$scope.resultGet = result;
}).error(function() {
console.log("error");
});
};
$scope.post = function(value) {
$http.post("http://localhost:4567/movie", { 'movie': value }).success(function(result) {
console.log(result);
$scope.resultPost = result;
}).error(function() {
console.log("error");
});
};
});
Yay, we got a new error :
OPTIONS http://localhost:4567/movie Request header field Content-Type is not allowed by Access-Control-Allow-Headers. angular.min.js:106
XMLHttpRequest cannot load http://localhost:4567/movie. Request header field Content-Type is not allowed by Access-Control-Allow-Headers.
So what’s wrong ?
The answer is in the error, we need to add Content-Type to the allowed headers :
headers 'Access-Control-Allow-Origin' => '*',
'Access-Control-Allow-Methods' => ['OPTIONS', 'GET', 'POST'],
'Access-Control-Allow-Headers' => 'Content-Type'
Now, Post requests are working. But the server doest not send back the submitted word. Instead, we receive : Object {result: null}
If we add a trace to check the received parameters on the server, we get, well nothing :
I, [2013-08-14T21:11:04.901188 #28960] INFO -- : Params : {}
That is due to how Angular.js handles the params to be sent with the post. Sinatra does not detect the params. We are going to do it by ourselves.
require 'sinatra'
require 'json'
use Rack::Logger
before do
content_type :json
headers 'Access-Control-Allow-Origin' => '*',
'Access-Control-Allow-Methods' => ['OPTIONS', 'GET', 'POST'],
'Access-Control-Allow-Headers' => 'Content-Type'
end
set :protection, false
options '/movie' do
200
end
get '/movie' do
{ result: "Monster University" }.to_json
end
post '/movie' do
begin
params.merge! JSON.parse(request.env["rack.input"].read)
rescue JSON::ParserError
logger.error "Cannot parse request body."
end
{ result: params[:movie], seen: true }.to_json
end
With this, it should work fine.
There is an other way to get the params, but they will be poorly formatted. You can add the following to app.js :
$httpProvider.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";
With this, we tell the server that our params come from a form. This is how Sinatra handles it :
I, [2013-08-14T21:42:05.648475 #30008] INFO -- : Params : {"{\"movie\":\"aaaa\",\"rating\":5,\"comment\":\"Super fun !\"}"=>nil}
As I told you, it’s kinda weird. Well, you can easily clean it up by getting the first key of the hash, parse it and get the params hash, that’s up to you.
Well, now you should be able to setup CORS calls between your client and your backend ! If you have any problem, feel free to contact me or leave a comment. It took me a while to figure out everything and I hope it will save you a lot of time. If you are interested in seeing PUT and DELETE calls, leave a comment and I will add it.
The code is available on Github.