Nesta etapa, você vai aprender:
- Como carregar recursos de fora do app e adicioná-los ao DOM por meio de XHR e URLs de objeto.
Tempo estimado para concluir esta etapa: 20 minutos.
Para conferir o que você vai concluir nesta etapa, vá até o final desta página ↓.
Como a CSP afeta o uso de recursos externos
A plataforma de apps do Chrome força o app a obedecer às Políticas de Segurança de Conteúdo (CSP). Não é possível carregar recursos DOM diretamente, como imagens, fontes e CSS, de fora do pacote de apps do Chrome.
Para mostrar uma imagem externa no app, solicite-a via XMLHttpRequest,
transforme-a em um Blob e crie um ObjectURL. Esse ObjectURL
pode ser adicionado ao
DOM porque se refere a um item na memória no contexto do app.
Mostrar imagens em miniatura para itens de tarefas
Vamos mudar o app para procurar URLs de imagem em um item de lista de tarefas. Se o URL se parecer com uma imagem (por exemplo, termina em .png, .jpg, .svg ou .gif), aplique o processo mencionado acima para mostrar uma miniatura da imagem ao lado do URL.
Atualizar permissões
Em um app do Chrome, é possível fazer chamadas XMLHttpRequest para qualquer URL, desde que você especifique o domínio dele no manifesto. Como você não sabe de antemão qual URL de imagem o usuário digitará, peça permissão para
fazer solicitações a "<all_urls>"
.
No manifest.json, solicite a permissão "
"permissions": ["storage", "alarms", "notifications",
"webview", "<all_urls>"],
Criar e limpar ObjectURLs
No controller.js, adicione um método _createObjectURL()
para criar ObjectURLs com base em um blob:
Controller.prototype._createObjectURL = function(blob) {
var objURL = URL.createObjectURL(blob);
this.objectURLs = this.objectURLs || [];
this.objectURLs.push(objURL);
return objURL;
};
ObjectURLs mantêm a memória, portanto, quando não precisar mais do ObjectURL, revogue-os. Adicione este método _clearObjectURL()
ao controller.js para processar isso:
Controller.prototype._clearObjectURL = function() {
if (this.objectURLs) {
this.objectURLs.forEach(function(objURL) {
URL.revokeObjectURL(objURL);
});
this.objectURLs = null;
}
};
Fazer uma solicitação XHR
Adicione um método _requestRemoteImageAndAppend()
para executar um XMLHttpRequest em um determinado URL de imagem:
Controller.prototype._requestRemoteImageAndAppend = function(imageUrl, element) {
var xhr = new XMLHttpRequest();
xhr.open('GET', imageUrl);
xhr.responseType = 'blob';
xhr.onload = function() {
var img = document.createElement('img');
img.setAttribute('data-src', imageUrl);
img.className = 'icon';
var objURL = this._createObjectURL(xhr.response);
img.setAttribute('src', objURL);
element.appendChild(img);
}.bind(this);
xhr.send();
};
No carregamento do XHR, esse método cria um ObjectURL
a partir da resposta do XHR e adiciona um elemento <img>
com esse ObjectURL
ao DOM.
Analisar URLs de imagem em itens de tarefas
Agora, adicione um método _parseForImageURLs()
que encontra todos os links ainda não processados e verifica se há
imagens. Para cada URL semelhante a uma imagem, execute _requestRemoteImageAndAppend()
:
Controller.prototype._parseForImageURLs = function () {
// remove old blobs to avoid memory leak:
this._clearObjectURL();
var links = this.$todoList.querySelectorAll('a[data-src]:not(.thumbnail)');
var re = /\.(png|jpg|jpeg|svg|gif)$/;
for (var i = 0; i<links.length; i++) {
var url = links[i].getAttribute('data-src');
if (re.test(url)) {
links[i].classList.add('thumbnail');
this._requestRemoteImageAndAppend(url, links[i]);
}
}
};
Renderizar miniaturas na lista de tarefas
Agora, chame _parseForImageURLs()
de showAll()
, showActive()
e showCompleted()
:
/**
* An event to fire on load. Will get all items and display them in the
* todo-list
*/
Controller.prototype.showAll = function () {
this.model.read(function (data) {
this.$todoList.innerHTML = this._parseForURLs(this.view.show(data));
this._parseForImageURLs();
}.bind(this));
};
/**
* Renders all active tasks
*/
Controller.prototype.showActive = function () {
this.model.read({ completed: 0 }, function (data) {
this.$todoList.innerHTML = this._parseForURLs(this.view.show(data));
this._parseForImageURLs();
}.bind(this));
};
/**
* Renders all completed tasks
*/
Controller.prototype.showCompleted = function () {
this.model.read({ completed: 1 }, function (data) {
this.$todoList.innerHTML = this._parseForURLs(this.view.show(data));
this._parseForImageURLs();
}.bind(this));
};
Faça o mesmo para editItem()
:
Controller.prototype.editItem = function (id, label) {
...
var onSaveHandler = function () {
...
if (value.length && !discarding) {
...
label.innerHTML = this._parseForURLs(value);
this._parseForImageURLs();
} else if (value.length === 0) {
...
}
Restringir as dimensões da imagem exibida
Por fim, em _bowercomponents/todomvc-common/base.css, adicione uma regra CSS para limitar o tamanho da imagem:
.thumbnail img[data-src] {
max-width: 100px;
max-height: 28px;
}
Iniciar o app Todo concluído
Você concluiu a Etapa 5! Atualize o app e adicione um item de tarefa com um URL para uma imagem hospedada on-line. Alguns URLs que você pode usar: http://goo.gl/nqHMF#.jpg ou http://goo.gl/HPBGR#.png.
Mais informações
Para informações mais detalhadas sobre algumas das APIs introduzidas nesta etapa, consulte:
Tudo pronto para passar à próxima etapa? Vá para a Etapa 6: exportar tarefas para o sistema de arquivos »