diff options
Diffstat (limited to 'files/pt-br/web/api/indexeddb_api')
3 files changed, 1697 insertions, 0 deletions
diff --git a/files/pt-br/web/api/indexeddb_api/basic_concepts_behind_indexeddb/index.html b/files/pt-br/web/api/indexeddb_api/basic_concepts_behind_indexeddb/index.html new file mode 100644 index 0000000000..c83b48750e --- /dev/null +++ b/files/pt-br/web/api/indexeddb_api/basic_concepts_behind_indexeddb/index.html @@ -0,0 +1,249 @@ +--- +title: Conceitos Básicos sobre IndexedDb +slug: Web/API/IndexedDB_API/Basic_Concepts_Behind_IndexedDB +tags: + - Avançado + - IndexedDB + - conceitos +translation_of: Web/API/IndexedDB_API/Basic_Concepts_Behind_IndexedDB +--- +<p>{{DefaultAPISidebar("IndexedDB")}}</p> + +<div class="summary"> +<p><strong>IndexedDB</strong> é uma forma de você armazenar dados no browser do usuário. <span lang="pt-PT">Permite criar aplicativos da Web com habilidades de consulta ricas, independentemente da disponibilidade da rede, esses aplicativos podem trabalhar on-line e off-line. IndexedDB é útil para aplicativos que armazenam uma grande quantidade de dados (por exemplo, um catálogo de DVDs em uma biblioteca de empréstimos) e aplicativos que não precisam de conectividade persistente à Internet para trabalhar (por exemplo, clientes de e-mail, listas de tarefas e Blocos de notas).</span></p> +</div> + +<h2 class="western" id="Sobre_esse_documento">Sobre esse documento</h2> + +<p>Essa introdução discute conceitos essenciais e a terminologia do IndexedDB. Ele vai ter dar um visão geral e explicar conceitos chaves.</p> + +<p>Você vai achar útil:</p> + +<ul> + <li> + <p style="margin-bottom: 0cm;">Para aprender mais sobre termos do IndexedDB, veja a seção <a href="#definitions">Definições</a>.</p> + </li> + <li> + <p style="margin-bottom: 0cm;">Para um tutorial detalhado de como usar a API, veja <a href="https://developer.mozilla.org/pt-BR/docs/IndexedDB/Usando_IndexedDB">Usando IndexedDB</a>.</p> + </li> + <li> + <p style="margin-bottom: 0cm;">Para obter a documentação da referência da API IndexedDB, volte para o artigo principal <a href="https://developer.mozilla.org/pt-BR/docs/IndexedDB">IndexedDB API</a> e suas sub-páginas, que documentam os tipos de objetos suportados pelo IndexedDB.</p> + </li> + <li> + <p>Para mais informações de como o navegador armazena seus dados em segundo plano, leia <a href="https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API/Browser_storage_limits_and_eviction_criteria">Browser storage limits and eviction criteria</a>.</p> + </li> +</ul> + +<h2 class="western" id="Visão_geral_do_IndexedDB">Visão geral do IndexedDB</h2> + +<p>IndexedDB permite você armazenar e consultar objetos que são indexados com uma chave. Todas as mudanças na base dados são feitas por transações. Como a maioria soluções de armazenamento web, IndexedDB segue a <a href="http://www.w3.org/Security/wiki/Same_Origin_Policy">política de mesma origem</a>. Então enquanto você pode acessar dados armazenados em um domínio, você não pode acessar em diferentes domínios.</p> + +<p>IndexedDB é uma API <a>assíncrona</a> que pode ser usada em diversos contextos, incluindo <a>WebWorkers</a>. Isso permite o uso de uma versão <a>síncrona</a> também, para o uso em web workers, mas isso foi removido da especificação por falta de interesse da comunidade web.</p> + +<p><br> + IndexedDB foi pensado para ser uma especificação concorrente ao banco de dados WebSQL, mas o W3C depreciou o WebSQL em 18 de novembro de 2010. Embora IndexedDB e WebSQL sejam soluções para armazenamento, eles não oferecem as mesmas funcionalidades. WebSQL Database é um sistema de acesso a banco de dados relacional, enquanto que IndexedDB é um sistema de tabelas indexadas.</p> + +<h2 class="western" id="Principais_conceitos">Principais conceitos</h2> + +<p> Se você já trabalhou com outros tipos de banco de dados, você pode esquecer enquanto trabalha com IndexedDB. E tenha esses importantes conceitos em mente:</p> + +<ul> + <li> + <p><strong>Bases de dados IndexedDB armazenam pares chave-valor.</strong> Os valores podem ser objetos de estruturas complexas, e chaves podem ser propriedades desses objetos. Você pode criar índices que usam qualquer propriedade dos objetos para pesquisa rápida, bem como enumerações ordenadas. As chaves podem ser objetos binários.</p> + </li> + <li> + <p><strong>IndexedDB é </strong><strong>construído</strong><strong> em um modelo de base de dado</strong><strong>s</strong><strong> transacional</strong>. Tudo o que você faz no IndexedDB sempre acontece no contexo de uma <a href="#gloss_transaction">transaction</a>. A API IndexedDB fornece uma série de objetos que representam índices, tabelas, cursores, assim por diante, mas cada um vinculado a uma transação. Assim, você não pode executar comandos ou abrir cursores fora de uma transação. As transações têm um tempo de vida bem definido, portanto, tentar usar uma transação após concluída irá gerar exceções. Além disso, as transações fazem commits automaticamente sem opção de se fazer manualmente.</p> + + <p>Esse modelo de transação é muito útil se você considerar que o usuário pode abrir duas instâncias da sua aplicação em duas diferentes abas simultaneamente. Sem as operações de transação, As duas instâncias poderiam interferir outras modificações. Se você não está familiarizado com transações no banco de dados, leia o <a href="https://en.wikipedia.org/wiki/Database_transaction">Wikipedia article on transactions</a>. Também veja <a href="#gloss_transaction">transaction</a> na seção de definições.</p> + </li> +</ul> + +<p style="margin-bottom: 0cm; line-height: 100%;"> </p> + +<ul> + <li> + <p><strong><span id="result_box" lang="pt"><span>A API IndexedDB é na maior parte assíncrona</span></span>.</strong> A API não retorna dados usando valores; em vez disso você deve passar uma função <a href="https://developer.mozilla.org/en-US/docs/Mozilla/js-ctypes/Using_js-ctypes/Declaring_and_Using_Callbacks">callback</a>. <span id="result_box" lang="pt"><span>Você não "armazena" um valor no banco de dados, ou "recupera" um valor do banco de dados através de meios síncronos.</span> <span>Em vez disso, você "solicita" que uma operação de banco de dados aconteça.</span> <span>Você será notificado por um evento DOM quando a operação for concluída e o tipo de evento recebido informará se a operação foi bem-sucedida ou falhou.</span> <span>Isto soa um pouco complicado no início, mas faz sentido no fundo. Não é tão diferente da maneira que </span></span><a href="/en/DOM/XMLHttpRequest" title="https://developer.mozilla.org/en/xmlhttprequest">XMLHttpRequest</a> funciona.</p> + </li> + <li> + <p><strong>IndexedDB usa várias requisições. </strong> <span id="result_box" lang="pt"><span>As </span></span>requisições <span lang="pt"><span>são objetos que recebem os eventos de sucesso ou falha do DOM mencionados anteriormente</span></span> . Eles têm propriedades <code style="font-size: 14px;">onsuccess</code> e <code style="font-size: 14px;">onerror</code>, e você pode chamar <code style="font-size: 14px;">addEventListener()</code> e <code style="font-size: 14px;">removeEventListener()</code> neles. Eles também tem as propriedades <code style="font-size: 14px;">readyState</code>, <code style="font-size: 14px;">result</code>, e <code style="font-size: 14px;">errorCode</code> que informam o status da requisição. A propriedade <code style="font-size: 14px;">result</code> é particurlamente mágica, pode ser muitas coisas diferentes , depende de como a requisção foi feita (por exemplo, uma instancia <code style="font-size: 14px;">IDBCursor</code>, ou uma chave para um valor que você inseriu na base).</p> + </li> + <li> + <p><span id="result_box" lang="pt"><span><strong>IndexedDB usa eventos DOM para notificá-lo quando os resultados estão disponíveis</strong>.</span> <span>Eventos DOM sempre têm um tipo propriedade (em IndexedDB, é mais comumente definido como "sucesso" ou "erro").</span> <span>Os eventos DOM também têm uma propriedade de destino que indica para onde o evento é dirigido.</span> <span>Na maioria dos casos, o destino de um evento é o objeto IDBRequest que foi gerado como resultado de alguma operação no banco de dados.</span> <span>Eventos de sucesso não disparam um evento em bolha (bubble up) e não podem ser cancelados.</span> <span>Eventos de erro, por outro lado, criam evento bolha que podem ser cancelados.</span> <span>Isso é muito importante, pois eventos de erro podem cancelar qualquer transações em que estejam rodando, a menos que elas sejam canceladas.</span></span></p> + </li> + <li> + <p><span id="result_box" lang="pt"><span><strong>IndexedDB é orientado a objetos</strong>.</span> <span>IndexedDB não é um banco de dados relacional com tabelas que representam coleções de linhas e colunas.</span> <span>Esta diferença importante e fundamental afeta a maneira como você projeta e constrói suas aplicações.</span></span></p> + + <p><span id="result_box" lang="pt"><span>Em um banco de dados relacional tradicional, você teria uma tabela que armazena uma coleção de linhas de dados e colunas de tipos de dados nomeados.</span> <span>IndexedDB, por outro lado, requer que você crie um armazenamento de objetos para um tipo de dado e simplesmente persista objetos JavaScript nesse armazenamento.</span> <span>Cada armazenamento de objeto pode ter uma coleção de índices que o torna eficiente para consultar e iterar</span></span>. Se você não está familiarizado com sitemas de banco de dados orientados a objetos, leia o artigo <a class="external" href="https://en.wikipedia.org/wiki/Object_database" title="http://en.wikipedia.org/wiki/Object_database">Wikipedia article on object database</a>.</p> + </li> + <li> + <p><strong>IndexedDB não usa Structured Query Language (<abbr>SQL</abbr>).</strong> <span id="result_box" lang="pt"><span>Ele usa consultas em um índice que produz um cursor, que você usa para iterar em todo o conjunto de resultados.</span> <span>Se você não estiver familiarizado com os sistemas NoSQL, leia o artigo</span></span> <a class="external" href="https://en.wikipedia.org/wiki/NoSQL" title="http://en.wikipedia.org/wiki/NoSQL">Wikipedia article on NoSQL</a>.</p> + </li> + <li> + <p><strong>IndexedDB segue a política de mesma origem</strong>. Uma origem equivale a um domínio, um protocolo de camada de aplicação e porta de uma URL de um documento de onde um script está sendo executado. Cada origem tem seu próprio conjunto de bancos de dados associados. Cada banco de dados tem um nome que o identifica dentro da origem.<br> + <br> + A restrição de segurança imposta sobre o IndexedDB previne que aplicações acessem dados de uma origem diferente. Por exemplo, enquanto um app ou página em <a class="external" href="http://www.example.com/app/" rel="freelink">http://www.exemplo.com/app/</a> pode obter dados de <a class="external" href="http://www.example.com/app/" rel="freelink">http://www.exemplo.com/dir/</a>, porque compartilham a mesma origem, ela não pode obter dados de <a class="external" href="http://www.example.com/app/" rel="freelink">http://www.exemplo.com:8080/app</a> (porta diferente) ou <a class="external" href="http://www.example.com/app/" rel="freelink">https://www.exemplo.com/app</a> (protocolo diferente), porque possuem diferentes origens.<br> + </p> + + <div class="note"><strong>Nota</strong>: O conteúdo de janelas de terceiros (por exemplo, {{htmlelement ("iframe")}} conteúdo) pode acessar o armazenamento IndexedDB para a origem em que está incorporado, a menos que o navegador esteja configurado para <a href="https://support.mozilla.org/en-US/kb/disable-third-party-cookies">nunca aceitar cookies de terceiros</a> (veja {{bug ("1147821 ")}}.)</div> + </li> +</ul> + +<h2 id="definitions" name="definitions">Definições</h2> + +<p>Essa seção define e explica os termos usado na API IndexedDB.</p> + +<h3 id="database" name="database">Base de dados</h3> + +<dl> + <dt>Base de dados</dt> + <dd>Um repositório de informação, normalmente é composto por um ou mais <a href="#gloss_object_store" title="#gloss_object_store"><em>object stores</em></a>. cada base de dados deve possuir: + <ul> + <li>Name. This identifies the database within a specific origin and stays constant throughout its lifetime. The name can be any string value (including an empty string).</li> + <li> + <p>Current <a href="#gloss_version"><em>version</em></a>. When a database is first created, its version is the integer 1 if not specified otherwise. Each database can have only one version at any given time.</p> + </li> + </ul> + </dd> + <dt><a name="durable">durable</a></dt> + <dd> + <p>In Firefox, IndexedDB used to be <strong>durable</strong>, meaning that in a readwrite transaction {{domxref("IDBTransaction.oncomplete")}} was fired only when all data was guaranteed to have been flushed to disk.</p> + + <p>As of Firefox 40, IndexedDB transactions have relaxed durability guarantees to increase performance (see {{Bug("1112702")}}), which is the same behaviour as other IndexedDB-supporting browsers. In this case the {{Event("complete")}} event is fired after the OS has been told to write the data but potentially before that data has actually been flushed to disk. The event may thus be delivered quicker than before, however, there exists a small chance that the entire transaction will be lost if the OS crashes or there is a loss of system power before the data is flushed to disk. Since such catastrophic events are rare, most consumers should not need to concern themselves further.</p> + + <div class="note"> + <p><strong>Note</strong>: In Firefox, if you wish to ensure durability for some reason (e.g. you're storing critical data that cannot be recomputed later) you can force a transaction to flush to disk before delivering the <code>complete</code> event by creating a transaction using the experimental (non-standard) <code>readwriteflush</code> mode (see {{domxref("IDBDatabase.transaction")}}.) This is currently experimental, and can only be used if the <code>dom.indexedDB.experimental</code> pref is set to <code>true</code> in <code>about:config</code>.</p> + </div> + </dd> + <dt><a name="gloss_object_store">object store</a></dt> + <dd> + <p>The mechanism by which data is stored in the database. The object store persistently holds records, which are key-value pairs. Records within an object store are sorted according to the <em><a href="#gloss_key">keys</a></em> in an ascending order.</p> + + <p>Every object store must have a name that is unique within its database. The object store can optionally have a <em><a href="#gloss_keygenerator">key generator</a></em> and a <em><a href="#gloss_keypath">key path</a></em>. If the object store has a key path, it is using <em><a href="#gloss_inline_key">in-line keys</a></em>; otherwise, it is using <em><a href="#gloss_outofline_key">out-of-line keys</a></em>.</p> + + <p>For the reference documentation on object store, see <a href="../../../../en/IndexedDB/IDBObjectStore" rel="internal">IDBObjectStore</a> or <a href="../../../../en/IndexedDB/IDBObjectStoreSync" rel="internal">IDBObjectStoreSync</a>.</p> + </dd> + <dt><a name="gloss_version">version</a></dt> + <dd>When a database is first created, its version is the integer 1. Each database has one version at a time; a database can't exist in multiple versions at once. The only way to change the version is by opening it with a greater version than the current one. This will start a <a href="/en-US/docs/Web/API/IDBVersionChangeRequest"><code>versionchange</code></a> <em>transaction</em> and fire an <a href="/en-US/docs/Web/Reference/Events/upgradeneeded_indexedDB"><code>upgradeneeded</code></a> event. The only place where the schema of the database can be updated is inside the handler of that event.</dd> + <dd>Note: This definition describes the <a class="external" href="http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html">most recent specification</a>, which is only implemented in up-to-date browsers. Old browsers implemented the now deprecated and removed <a href="/en-US/docs/IndexedDB/IDBDatabase#setVersion()" title="/en-US/docs/IndexedDB/IDBDatabase#setVersion()"><code>IDBDatabase.setVersion()</code></a> method.</dd> + <dt><a name="gloss_database_connection">database connection</a></dt> + <dd>An operation created by opening a <em><a href="#gloss_database">database</a></em>. A given database can have multiple connections at the same time.</dd> + <dt><a name="gloss_transaction">transaction</a></dt> + <dd> + <p>An atomic set of data-access and data-modification operations on a particular database. It is how you interact with the data in a database. In fact, any reading or changing of data in the database must happen in a transaction.</p> + + <p>A database connection can have several active transaction associated with it at a time, so long as the writing transactions do not have overlapping <a href="#scope"><em>scopes</em></a>. The scope of transactions, which is defined at creation, determines which object stores the transaction can interact with and remains constant for the lifetime of the transaction. So, for example, if a database connection already has a writing transaction with a scope that just covers the <code>flyingMonkey</code> object store, you can start a second transaction with a scope of the <code>unicornCentaur</code> and <code>unicornPegasus</code> object stores. As for reading transactions, you can have several of them — even overlapping ones.</p> + + <p>Transactions are expected to be short-lived, so the browser can terminate a transaction that takes too long, in order to free up storage resources that the long-running transaction has locked. You can abort the transaction, which rolls back the changes made to the database in the transaction. And you don't even have to wait for the transaction to start or be active to abort it.</p> + + <p>The three modes of transactions are: <code>readwrite</code>, <code>readonly</code>, and <code>versionchange</code>. The only way to create and delete object stores and indexes is by using a <a href="/en-US/docs/Web/Reference/Events/versionchange_indexedDB"><code>versionchange</code></a> transaction. To learn more about transaction types, see the reference article for <a href="/en/IndexedDB" title="https://developer.mozilla.org/en/IndexedDB">IndexedDB</a>.</p> + + <p>Because everything happens within a transaction, it is a very important concept in IndexedDB. To learn more about transactions, especially on how they relate to versioning, see <a href="../../../../en/IndexedDB/IDBTransaction" rel="internal">IDBTransaction</a>, which also has reference documentation. For the documentation on the synchronous API, see <a href="../../../../en/IndexedDB/IDBTransactionSync" rel="internal">IDBTransactionSync</a>.</p> + </dd> + <dt><a name="gloss_request">request</a></dt> + <dd>The operation by which reading and writing on a database is done. Every request represents one read or write operation.</dd> + <dt><a name="gloss_index">index</a></dt> + <dd> + <p>An index is a specialized object store for looking up records in another object store, called the <em>referenced object store</em>. The index is a persistent key-value storage where the value part of its records is the key part of a record in the referenced object store. The records in an index are automatically populated whenever records in the referenced object store are inserted, updated, or deleted. Each record in an index can point to only one record in its referenced object store, but several indexes can reference the same object store. When the object store changes, all indexes that refer to the object store are automatically updated.</p> + + <p>Alternatively, you can also look up records in an object store using the <a href="#gloss_key"> key</a><em>.</em></p> + + <p>To learn more on using indexes, see <a href="/en/IndexedDB/Using_IndexedDB#Using_an_index" title="en/IndexedDB/Using_IndexedDB#Using_an_index">Using IndexedDB</a>. For the reference documentation on index, see <a href="../../../../en/IndexedDB/IDBKeyRange" rel="internal">IDBKeyRange</a>.</p> + </dd> +</dl> + +<h3 id="key" name="key">Chave e valor</h3> + +<dl> + <dt><a name="gloss_key">key</a></dt> + <dd> + <p>A data value by which stored values are organized and retrieved in the object store. The object store can derive the key from one of three sources: a <em><a href="#gloss_keygenerator">key generator</a></em>, a <em><a href="#gloss_keypath">key path</a></em>, or an explicitly specified value. The key must be of a data type that has a number that is greater than the one before it. Each record in an object store must have a key that is unique within the same store, so you cannot have multiple records with the same key in a given object store.</p> + + <p>A key can be one of the following types: <a href="/en/JavaScript/Reference/Global_Objects/String" title="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String">string</a>, <a href="/en/JavaScript/Reference/Global_Objects/Date" title="en/JavaScript/Reference/Global Objects/Date">date</a>, float, a binary blob, and <a href="/en/JavaScript/Reference/Global_Objects/Array" title="en/JavaScript/Reference/Global Objects/Array">array</a>. For arrays, the key can range from an empty value to infinity. And you can include an array within an array.</p> + + <p>Alternatively, you can also look up records in an object store using the <em><a href="#gloss_index">index</a>.</em></p> + </dd> + <dt><a name="gloss_keygenerator">key generator</a></dt> + <dd>A mechanism for producing new keys in an ordered sequence. If an object store does not have a key generator, then the application must provide keys for records being stored. Generators are not shared between stores. This is more a browser implementation detail, because in web development, you don't really create or access key generators.</dd> + <dt><a name="gloss_inline_key">in-line key</a></dt> + <dd>A key that is stored as part of the stored value. It is found using a <em>key path</em>. An in-line key can be generated using a generator. After the key has been generated, it can then be stored in the value using the key path or it can also be used as a key.</dd> + <dt><a name="gloss_outofline_key">out-of-line key</a></dt> + <dd>A key that is stored separately from the value being stored.</dd> + <dt><a name="gloss_keypath">key path</a></dt> + <dd>Defines where the browser should extract the key from in the object store or index. A valid key path can include one of the following: an empty string, a JavaScript identifier, or multiple JavaScript identifiers separated by periods or an array containing any of those. It cannot include spaces.</dd> + <dt><a name="gloss_value">value</a></dt> + <dd> + <p>Each record has a value, which could include anything that can be expressed in JavaScript, including <a href="/en/JavaScript/Reference/Global_Objects/Boolean" rel="internal" title="en/JavaScript/Reference/Global_Objects/Boolean">boolean</a>, <a href="/en/JavaScript/Reference/Global_Objects/Number" rel="internal" title="en/JavaScript/Reference/Global_Objects/Number">number</a>, <a href="/en/JavaScript/Reference/Global_Objects/String" title="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String">string</a>, <a href="/en/JavaScript/Reference/Global_Objects/Date" title="en/JavaScript/Reference/Global Objects/Date">date</a>, <a href="/en/JavaScript/Reference/Global_Objects/Object" title="en/JavaScript/Reference/Global Objects/Object">object</a>, <a href="/en/JavaScript/Reference/Global_Objects/Array" rel="internal" title="en/JavaScript/Reference/Global_Objects/Array">array</a>, <a href="/en/JavaScript/Reference/Global_Objects/RegExp" rel="internal" title="en/JavaScript/Reference/Global_Objects/RegExp">regexp</a>, <a href="/en/JavaScript/Reference/Global_Objects/undefined" title="en/JavaScript/Reference/Global_Objects/undefined">undefined</a>, and null.</p> + + <p>When an object or array is stored, the properties and values in that object or array can also be anything that is a valid value.</p> + + <p><a href="/en/DOM/Blob" title="en/DOM/Blob">Blobs</a> and files can be stored, cf. <a class="external" href="http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html">specification</a> {{ fx_minversion_inline("11") }}.</p> + </dd> +</dl> + +<h3 id="range" name="range">Intervalo e escopo</h3> + +<dl> + <dt id="scope"><a id="gloss_scope" name="gloss_scope">scope</a></dt> + <dd>The set of object stores and indexes to which a transaction applies. The scopes of read-only transactions can overlap and execute at the same time. On the other hand, the scopes of writing transactions cannot overlap. You can still start several transactions with the same scope at the same time, but they just queue up and execute one after another.</dd> + <dt id="cursor"><a id="gloss_cursor" name="gloss_cursor">cursor</a></dt> + <dd>A mechanism for iterating over multiple records with a <em>key range</em>. The cursor has a source that indicates which index or object store it is iterating. It has a position within the range, and moves in a direction that is increasing or decreasing in the order of record keys. For the reference documentation on cursors, see <a href="../../../../en/IndexedDB/IDBCursor" rel="internal">IDBCursor</a> or <a href="../../../../en/IndexedDB/IDBCursorSync" rel="internal">IDBCursorSync</a>.</dd> + <dt id="key_range"><a id="gloss_keyrange" name="gloss_keyrange">key range</a></dt> + <dd> + <p>A continuous interval over some data type used for keys. Records can be retrieved from object stores and indexes using keys or a range of keys. You can limit or filter the range using lower and upper bounds. For example, you can iterate over all values of a key between x and y.</p> + + <p>For the reference documentation on key range, see <a href="../../../../en/IndexedDB/IDBKeyRange" rel="internal">IDBKeyRange</a>.</p> + </dd> +</dl> + +<h2 id="limitations" name="limitations">Limitações</h2> + +<p>IndexedDB is designed to cover most cases that need client-side storage. However, it is not designed for a few cases like the following:</p> + +<ul> + <li>Internationalized sorting. Not all languages sort strings in the same way, so internationalized sorting is not supported. While the database can't store data in a specific internationalized order, you can sort the data that you've read out of the database yourself. Note, however, that <a href="/en-US/docs/Web/API/IndexedDB_API/Using_IndexedDB#Locale-aware_sorting">locale-aware sorting</a> has been allowed with an experimental flag enabled (currently for Firefox only) since Firefox 43.</li> + <li>Synchronizing. The API is not designed to take care of synchronizing with a server-side database. You have to write code that synchronizes a client-side indexedDB database with a server-side database.</li> + <li>Full text searching. The API<span style="direction: ltr;"> does not have an</span><span style="direction: ltr;"> equivalent of the <code>LIKE</code> operator in SQL. </span></li> +</ul> + +<p>In addition, be aware that browsers can wipe out the database, such as in the following conditions:</p> + +<ul> + <li>The user requests a wipe out. Many browsers have settings that let users wipe all data stored for a given website, including cookies, bookmarks, stored passwords, and IndexedDB data.</li> + <li>The browser is in private browsing mode. Some browsers, have "private browsing" (Firefox) or "incognito" (Chrome) modes. At the end of the session, the browser wipes out the database.</li> + <li>The disk or quota limit has been reached.</li> + <li>The data is corrupt.</li> + <li>An incompatible change is made to the feature.</li> +</ul> + +<p>The exact circumstances and browser capabilities change over time, but the general philosophy of the browser vendors is to make the best effort to keep the data when possible.</p> + +<h2 id="next" name="next">Próximos passos</h2> + +<p>With these big concepts under our belts, we can get to more concrete stuff. For a tutorial on how to use the API, see <a href="/en/IndexedDB/Using_IndexedDB" title="en/IndexedDB/IndexedDB primer">Using IndexedDB</a>.</p> + +<h2 id="See_also">See also</h2> + +<p>Especificação</p> + +<ul> + <li><a href="http://www.w3.org/TR/IndexedDB/" title="http://www.w3.org/TR/IndexedDB/"><span style="direction: ltr;">Indexed Database API Specification</span></a></li> +</ul> + +<p>Referência</p> + +<ul> + <li><a href="/en/IndexedDB" title="https://developer.mozilla.org/en/IndexedDB">IndexedDB API Reference</a></li> +</ul> + +<p>Tutoriais</p> + +<ul> + <li><a href="/en/IndexedDB/Using_IndexedDB" title="en/IndexedDB/IndexedDB primer">Using IndexedDB</a></li> + <li><a class="external" href="http://www.html5rocks.com/en/tutorials/indexeddb/todo/" title="http://www.html5rocks.com/tutorials/indexeddb/todo/">A simple TODO list using HTML5 IndexedDB</a><span class="external">. </span><span class="external"> {{ Note("This example uses an old version of the spec and does not work on up-to-date browsers - it still uses the removed <code>setVersion()</code> method.") }}</span></li> +</ul> + +<p>Artigo relacionado</p> + +<ul> + <li><a class="external" href="http://msdn.microsoft.com/en-us/scriptjunkie/gg679063.aspx" title="http://msdn.microsoft.com/en-us/scriptjunkie/gg679063.aspx">IndexedDB — The Store in Your Browser</a></li> +</ul> diff --git a/files/pt-br/web/api/indexeddb_api/index.html b/files/pt-br/web/api/indexeddb_api/index.html new file mode 100644 index 0000000000..06e84254f2 --- /dev/null +++ b/files/pt-br/web/api/indexeddb_api/index.html @@ -0,0 +1,167 @@ +--- +title: IndexedDB +slug: Web/API/IndexedDB_API +translation_of: Web/API/IndexedDB_API +--- +<div class="summary"> +<p>IndexedDB é uma API para armazenamento client-side de quantidades significantes de informações e buscas com alta performance por índices. Enquanto <a href="https://developer.mozilla.org/pt-BR/docs/DOM/Storage">DOM Storage</a> é útil para armazenamento de pequenas quantidade de dados, IndexedDB é a solução para grande porção de dados estruturados.</p> +</div> + +<p>Esta página basicamente é o ponto de entrada para uma descrição técnica dos objetos da API. Precisando de suporte ainda mais inicial consulte os <a href="https://developer.mozilla.org/en-US/docs/IndexedDB/Basic_Concepts_Behind_IndexedDB">Conceitos Básicos sobre IndexedDb</a>. Para mais detalhes sobre a implementação, veja <a href="https://developer.mozilla.org/en-US/docs/IndexedDB/Using_IndexedDB">Usando IndexedDB</a>.<br> + <br> + IndexedDB provém APIs separadas para acesso tanto síncrono quanto assíncrono. As APIs síncronas devem ser utilizadas apenas dentro de <a href="https://developer.mozilla.org/en-US/docs/DOM/Worker">Web Workers</a>, apesar de não ser implementada por nenhum navegador atualmente. A API assíncrona funciona tanto com ou sem Web Workers, sendo que o Firefox ainda não implementou este.</p> + +<h2 id="API_Assíncrona">API Assíncrona</h2> + +<p>Os métodos da API assíncrona são chamados sem bloquear a thread que os chama. Para obter acesso assíncrono à database, chame <a href="https://developer.mozilla.org/en-US/docs/Web/API/IDBFactory.open">open()</a> no atributo <a href="https://developer.mozilla.org/en-US/docs/Web/API/IDBEnvironment.indexedDB">indexedDB</a> do objeto <a href="https://developer.mozilla.org/en-US/docs/DOM/window">window</a>, que retornará um objeto {{domxref("IDBRequest")}}. Operações assíncronas comunicam-se com a aplicação que os chamam executando eventos nos objetos {{domxref("IDBRequest")}}.</p> + +<div class="note"> +<p>Nota: O objeto indexedDB é prefixado em navegadores mais antigos (propriedade mozIndexedDB em Gecko < 16, webkitIndexedDb em Chrome e msIndexedDB no IE 10).</p> +</div> + +<p>As interfaces da API assíncrona do IndexedDB são:</p> + +<dl> + <dt>{{domxref("IDBFactory")}}</dt> + <dd>Provém acesso ao banco de dados. É a interface implementado pelo objeto global indexedDB e é, portanto, o ponto de entrada para API.</dd> + <dt>{{domxref("IDBCursor")}}</dt> + <dd>Itera sobre objectStores e índices</dd> + <dt>{{domxref("IDBCursorWithValue")}}</dt> + <dd>Itera sobre objectStores e índices e retorna o atual valor do cursor</dd> + <dt>{{domxref("IDBDatabase")}}</dt> + <dd>Represents a connection to a database. It's the only way to get a transaction on the database.</dd> + <dt>{{domxref("IDBEnvironment")}}</dt> + <dd>Provides access to a client-side database. It is implemented by the {{ domxref("window") }} and {{ domxref("worker") }} objects.</dd> + <dt>{{domxref("IDBIndex")}}</dt> + <dd>Provides access to the metadata of an index.</dd> + <dt>{{domxref("IDBKeyRange")}}</dt> + <dd>Define um alcance das chaves.</dd> + <dt>{{domxref("IDBObjectStore")}}</dt> + <dd>Representa um ObjectStore</dd> + <dt>{{domxref("IDBOpenDBRequest")}}</dt> + <dd>Representa uma requisição para abrir o banco de dados.</dd> + <dt>{{domxref("IDBRequest")}}</dt> + <dd>Provém acesso a resultados de requisições assíncronas ao banco de dados e a objetos do banco de dados. É o que você obtém quando chama um método assíncrono.</dd> + <dt>{{domxref("IDBTransaction")}}</dt> + <dd>Representa uma transação. Você cria a transação no banco de dados, especifíca o escopo (tal como qual objectStore você deseja acessar), e determina que tipo de acesso (apenas leitura ou também escrita) daquilo que você deseja.</dd> +</dl> + +<ul> +</ul> + +<p>Uma versão anterior da especificação também define estas interfaces agora removidas. Elas ainda estão documentadas caso você precise atualizar códigos escritos anteriormente:</p> + +<dl> + <dt>{{domxref("IDBVersionChangeRequest")}}</dt> + <dd>Representa uma requisição para alterar a versão do banco de dados. O modo de alterar a versão do banco de dados mudou então (chamando IDBFactory.open sem também chamar IDBDatabase.setVersion) e a interface IDBOpenDBRequest agora tem a funcionalidade do removido IDBVersionChangeRequest.</dd> + <dt>{{domxref("IDBDatabaseException")}} {{ obsolete_inline() }}</dt> + <dd>Representa condições de erro que podem ser encontradas enquanto performando operações no banco de dados.</dd> +</dl> + +<ul> +</ul> + +<div class="note"> +<p> <strong>Nota</strong>: há também a <a href="https://developer.mozilla.org/en-US/docs/IndexedDB/Syncronous_API">versão síncrona da API</a>. A versão síncrona não tem implementação em qualquer navegador. É feita para ser utilizada com <a href="https://developer.mozilla.org/en-US/docs/DOM/Using_web_workers">WebWorkers</a>.</p> +</div> + +<h2 id="Limites_de_Armazenamento">Limites de Armazenamento</h2> + +<p>Não há qualquer limite em um único elemento da database. Entretanto podem haver limites quanto ao tamanho de cada banco de dados. Este limite (e a maneira com qual o usuário chega a ele) pode variar de um navegador para outro:</p> + +<ul> + <li> + <p>Firefox: não há limite no tamanho do banco de dados. A interface do usuário irá apenas pedir a permissão para armazenar conjuntos com tamanho maior que 50mb. Este limite de tamanho pode ser customizado através da preferência dom.indexedDB.warningQuota (que é definida em <a href="http://mxr.mozilla.org/mozilla-central/source/modules/libpref/src/init/all.js" title="http://mxr.mozilla.org/mozilla-central/source/modules/libpref/src/init/all.js">http://mxr.mozilla.org/mozilla-central/source/modules/libpref/src/init/all.js</a>).</p> + </li> + <li> + <p>Google Chrome: veja <a class="link-https" href="https://developers.google.com/chrome/whitepapers/storage#temporary" rel="freelink">https://developers.google.com/chrome...rage#temporary</a></p> + </li> +</ul> + +<h2 id="Example" name="Example">Exemplos</h2> + +<ul> + <li>Um grande exemplo de para o que o indexedDb pode ser utilizado na web é o exemplo do Marco Castelluccion, vencedor do IndexedDB Mozilla DevDerby. A demonstração vencedora foi o eLibri, uma aplicação biblioteca e leitora de Ebook.</li> + <li>Você deveria também checar a referência de aplicações exemplo neste documento de referências: <a href="https://github.com/chrisdavidmills/to-do-notifications/tree/gh-pages">Notificações de A Fazer</a> (<a href="http://chrisdavidmills.github.io/to-do-notifications/">veja ao vivo</a>). Nem todo fragmento de código aparece neste exemplo, mas todo exemplo usa a mesma estrutura de dados e sintaxe, e fará sentido no contexto da aplicação.</li> +</ul> + +<h2 id="Browser_compatibility" name="Browser_compatibility">Compatibilidade dos navegadores</h2> + +<p>{{ CompatibilityTable() }}</p> + +<div id="compat-desktop"> +<table class="compat-table"> + <tbody> + <tr> + <th>Característica</th> + <th>Chrome</th> + <th>Firefox (Gecko)</th> + <th>Internet Explorer</th> + <th>Opera</th> + <th>Safari (WebKit)</th> + </tr> + <tr> + <td>API Assíncrona</td> + <td> + <p>11.0 {{ property_prefix("webkit") }}<br> + 24</p> + </td> + <td>{{ CompatGeckoDesktop("2.0") }} {{ property_prefix("moz") }}<br> + {{ CompatGeckoDesktop("16.0") }}</td> + <td>10</td> + <td>17</td> + <td>11.1</td> + </tr> + <tr> + <td>API Síncrona (com <a href="https://developer.mozilla.org/en-US/docs/DOM/Using_web_workers">WebWorkers</a>)</td> + <td>{{ CompatNo() }}</td> + <td>{{ CompatNo() }}<br> + See {{ bug(701634) }}</td> + <td>{{ CompatNo() }}</td> + <td>{{ CompatNo() }}</td> + <td>{{ CompatNo() }}</td> + </tr> + </tbody> +</table> +</div> + +<div id="compat-mobile"> +<table class="compat-table"> + <tbody> + <tr> + <th>Feature</th> + <th>Android</th> + <th>Firefox Mobile (Gecko)</th> + <th>IE Phone</th> + <th>Opera Mobile</th> + <th>Safari Mobile</th> + </tr> + <tr> + <td>API Assíncrona</td> + <td>4.4</td> + <td>{{ CompatGeckoDesktop("6.0") }} {{ property_prefix("moz") }}<br> + {{ CompatGeckoDesktop("16.0") }}</td> + <td>10</td> + <td>17</td> + <td>10.3</td> + </tr> + </tbody> +</table> +</div> + +<div class="note"> +<p>Nota: alguns browsers ainda não suportam IndexedDB mas suportam WebSQL, mais especificamente Safari/Webkit no desktop e iOS. Uma maneira de driblar este problema é utilizar IndexedDB Polyfill ou Shim, que recorre ao WebSQL para navegadores que não suportam.</p> +</div> + +<h2 id="Veja_Também">Veja Também</h2> + +<ul> + <li><a href="/en-US/docs/IndexedDB/Basic_Concepts_Behind_IndexedDB" title="en-US/docs/IndexedDB/Basic Concepts Behind IndexedDB">Conceitos Básicos sobre IndexedDB</a></li> + <li><a href="/en-US/docs/IndexedDB/Using_IndexedDB" title="en-US/docs/IndexedDB/IndexedDB primer">Utilizando IndexedDB</a></li> + <li><a class="external" href="http://hacks.mozilla.org/2012/02/storing-images-and-files-in-indexeddb/" title="http://hacks.mozilla.org/2012/02/storing-images-and-files-in-indexeddb/">Armazenando Imagens e Arquivos com IndexedDB</a></li> + <li><a class="external" href="http://www.w3.org/TR/IndexedDB/" title="http://www.w3.org/TR/IndexedDB/">Especificação da API de Indexed Database</a></li> + <li><a class="external" href="http://msdn.microsoft.com/en-us/scriptjunkie/gg679063.aspx" title="http://msdn.microsoft.com/en-us/scriptjunkie/gg679063.aspx">IndexedDB — O armazenamento em seu Navegador</a></li> + <li><a class="external" href="http://nparashuram.com/IndexedDB/trialtool/index.html" title="http://nparashuram.com/IndexedDB/trialtool/index.html">IndexedDB Exemplos</a></li> + <li><a href="https://github.com/axemclion/IndexedDBShim" title="https://github.com/axemclion/IndexedDBShim">IndexedDB Polyfill/Shim</a> para navegadores que apenas suportam WebSQL (e.g. mobile WebKit)</li> + <li><a href="http://nparashuram.com/IndexedDBShim/" title="http://nparashuram.com/IndexedDBShim/">JQuery IndexedDB plugin</a></li> +</ul> diff --git a/files/pt-br/web/api/indexeddb_api/usando_indexeddb/index.html b/files/pt-br/web/api/indexeddb_api/usando_indexeddb/index.html new file mode 100644 index 0000000000..da14879b31 --- /dev/null +++ b/files/pt-br/web/api/indexeddb_api/usando_indexeddb/index.html @@ -0,0 +1,1281 @@ +--- +title: Usando IndexedDB +slug: Web/API/IndexedDB_API/Usando_IndexedDB +tags: + - API IndexedDB Tutorial Avançado +translation_of: Web/API/IndexedDB_API/Using_IndexedDB +--- +<div class="summary"> +<p>IndexedDB é uma forma de armazenar dados no navegador do usuário. Com ele você pode criar aplicações web com possibilidade de fazer query sem necessidade de conexão, suas aplicações podem funcionar tanto online quanto offline. </p> +</div> + +<h2 id="Sobre_esse_documento">Sobre esse documento</h2> + +<p>Esse tutorial utiliza a API assíncrona do IndexedDB. Se você não está familiarizado com IndexedDB, você pode ler <a href="/pt-BR/docs/IndexedDB/Basic_Concepts_Behind_IndexedDB">Conceitos básicos sobre IndexedDB</a>.</p> + +<p>Para a documentação de referência, veja o artigo sobre <a href="/pt-BR/docs/IndexedDB" title="https://developer.mozilla.org/en/IndexedDB">API IndexedDB</a>, pois nele contém os tipos de objetos utilizados no IndexedDB, como também métodos da API, tanto síncrona como assíncrona. </p> + +<h2 id="pattern" name="pattern">Padrão básico</h2> + +<p>O IndexedDB encoraja o uso do seguinte padrão:</p> + +<ol> + <li>Abrir um banco de dados.</li> + <li>Criar um ObjectStore ao atualizar o banco. </li> + <li>Iniciar uma transação e e faz um request para fazer alguma operação no banco, como adicionar ou obter dados.</li> + <li> + <div>Esperar a operação ser completada ouvindo algum evento DOM.</div> + </li> + <li> + <div>Fazer algo com o resultado da query (que pode ser obtida pelo objeto request).</div> + </li> +</ol> + +<p>OK, então, agora com esses conceitos em mente, nós podemos fazer coisas mais concretas.</p> + +<h2 id="open" name="open">Criando e estruturando o banco</h2> + +<p>Pelo fato da especificação ainda estar evoluindo, as implementações do IndexedDB tem prefixos de navegadores. Os navegadores podem ter implementações diferentes da API IndexedDB até a especificação ser consolidada. Mas uma vez que tudo chegar a um consenso, os navegadores tirarão seus prefixos. Atualmente, algumas implementações removeram o prefixo: Internet Explorer 10, Firefox 16, Chrome 24. Quando eles usam prefixo, navegadores baseados no Gecko usam o prefixo <code>moz</code>, enquanto os navegadores baseados no WebKit usam o prefixo <code>webkit</code>.</p> + +<h3 id="Usando_uma_versão_experimental_do_IndexedDB">Usando uma versão experimental do IndexedDB</h3> + +<p>Se você quiser testar seu código em navegadores que usam prefixo, você pode usar o código abaixo: </p> + +<pre class="brush: js">// Na linha abaixo, você deve incluir os prefixos do navegador que você vai testar. +window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB; +// Não use "var indexedDB = ..." se você não está numa function. +// Posteriormente, você pode precisar de referências de algum objeto window.IDB*: +window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction; +window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange; +// (Mozilla nunca usou prefixo nesses objetos, então não precisamos window.mozIDB*)</pre> + +<p>Tome cuidado, implementações prefixadas podem estar com bugs ou implementando especificações antigas. Portanto, não é recomendado usar em produção. É preferível não usar IndexedDB em navegadores antigos:</p> + +<pre class="brush: js">if (!window.indexedDB) { + window.alert("Seu navegador não suporta uma versão estável do IndexedDB. Alguns recursos não estarão disponíveis."); +} +</pre> + +<h3 id="Abrindo_um_banco">Abrindo um banco</h3> + +<p>Começamos todo o processo assim:</p> + +<pre class="brush: js">// Abrindo o banco de dados +var request = window.indexedDB.open("DBteste", 3); +</pre> + +<p>Abrir um banco é como qualquer outra operação — Você tem que "requerer (request)".</p> + +<p>A requisição de abertura não abre o banco ou inicia a transação. A chamada da função <code>open()</code> retorna um objeto <a href="/en-US/docs/IndexedDB/IDBOpenDBRequest" title="/en-US/docs/IndexedDB/IDBOpenDBRequest"><code>IDBOpenDBRequest</code></a> com o resultado (success) ou um erro que você terá que tratar. Muitas outras funções assíncronas no IndexedDB fazem a mesma coisa - retornam um objeto <a href="/en-US/docs/IndexedDB/IDBRequest" title="/en-US/docs/IndexedDB/IDBRequest"><code style="font-size: 14px; color: rgb(51, 51, 51);">IDBRequest</code></a> com o resultado ou erro. O resultado para a função open é uma instância de <code style="font-size: 14px; color: rgb(51, 51, 51);"><a href="/en-US/docs/IndexedDB/IDBDatabase" title="/en-US/docs/IndexedDB/IDBDatabase">IDBDatabase</a>.</code></p> + +<p>O segundo parâmetro para o método open é a versão do banco. A versão do banco determina seu schema — os registros no banco e sua estrutura. Se o banco não existe ainda, ele é criado pela operação <code>open</code>, então o evento<code> onupgradeneeded </code>é chamado e você cria o schema do banco nesse evento. Se o banco existe mas você está fornecendo um novo número de versão, o evento <code>onupgradeneeded </code>é chamado imediatamente, permitindo você tratar a atualização do schema. Para mais informações sobre isso veja <a href="#Updating_the_version_of_the_database">Updating the version of the database</a>.</p> + +<div class="warning"> +<p>O número de versão é um <code>unsigned long long</code>, o que significa que ele pode ver um inteiro muito grande. Isso também significa que você não pode usar float, pois ele será convertido em um inteiro pequeno e a transação pode não acontecer, ou o evento <code>upgradeneeded</code> pode não ser chamado. Então se você usar 2.4 como versão:</p> + +<pre class="brush: js">var request = indexedDB.open("DBteste", 2.4); // não faça isso, pois a versão será convertida para 2.</pre> +</div> + +<h4 id="Gerenciando_handlers">Gerenciando handlers</h4> + +<p>A primeira coisa que você vai querer fazer em quase todos os requests é tratar os casos de success e error:</p> + +<pre class="brush: js">request.onerror = function(event) { + // Fazer algo com request.errorCode! +}; +request.onsuccess = function(event) { + // Fazer algo com request.result! +};</pre> + +<p>Qual das duas funções, <code>onsuccess()</code> ou <code>onerror()</code>, será chamada? Se tudo correr bem, o evento de sucesso (que é um evento DOM event com propriedade <code>type</code> setada <code>"success"</code>) é chamado com <code>request</code> como seu <code>target</code>. Uma vez chamado, a função <code>onsuccess()</code> no <code>request</code> é chamada com o evento de sucesso em seu contexto. Por outro lado, se acontecer algum problema, um evento de erro (que é um evento DOM com a propriedade <code>type</code> setada para <code>"error"</code>) é chamado no <code>request</code>. Então a função <code><code>onerror()</code></code> com o evento erro em seu contexto.</p> + +<p>A API IndexedDB é feita para minimizar a necessidade de manipular erros, então você não fará muitos eventos de erro (ao menos, se você usar a API!) No caso de abrir um banco, portanto, existe algumas condições comuns para eventos de erro. O problema mais comum é o usuário não dar permissão para criar o banco. Um dos principais objetivos do IndexedDB é permitir muitos dados serem armazenados para uso offline. (Para aprender mais sobre o quanto cada navegador pode armazenar, veja <a href="/en/IndexedDB#Storage_limits" title="https://developer.mozilla.org/en/IndexedDB#Storage_limits">Storage limits</a>). </p> + +<p>Obviamente, navegadores não querem armazenar dados que poluem seu computador, então o navegador mostra uma mensagem ao usuário na primeira vez que um aplicativo tenta abrir o IndexedDB. O usuário pode escolher permitir ou negar acesso. O IndexedDB também é desabilitado no modo privado dos navegadores (ctrl+shift+N no Chrome e ctrl+shift+P no Firefox). Isso acontece porque o intuito do modo privado é não deixar rastros na navegação.</p> + +<p>Agora, assumindo que o usuário aprovou seu request para criar o banco, e você recebeu success; Qual é o próximo passo? O request foi gerado com a chamada de <code>indexedDB.open()</code>, e <code>request.result</code> é uma instância de <code>IDBDatabase</code>, e você definitivamente vai querer armazenar isso para usar depois. Veja abaixo:</p> + +<pre class="brush: js">var db; +var request = indexedDB.open("DBteste"); +request.onerror = function(event) { + alert("Você não habilitou minha web app para usar IndexedDB?!"); +}; +request.onsuccess = function(event) { + db = request.result; +}; +</pre> + +<h4 id="Tratando_Erros">Tratando Erros</h4> + +<p>Como mencionado acima, o evento de erro é chamado quando o request dá erro. Se você quer evitar manipuladores de erro a cada request, você pode adicionar um único manipulador de erro no objeto db, como abaixo:</p> + +<pre class="brush: js">db.onerror = function(event) { + // Função genérica para tratar os erros de todos os requests desse banco! + alert("Database error: " + event.target.errorCode); +}; +</pre> + +<p>Um dos erros mais comuns ao abrir o banco é <code>VER_ERR</code>. Ele indica que a versão do banco existente é maior que a versão que você quer abrir.</p> + +<h3 id="Criando_ou_atualizando_a_versão_do_banco">Criando ou atualizando a versão do banco</h3> + +<p><a name="Updating_the_version_of_the_database"></a>Quando você cria um novo banco ou aumenta sua versão, o evento <code style="font-size: 14px; color: rgb(51, 51, 51);">onupgradeneeded</code><span style="line-height: 21px;"> será chamado. No manipulador deste evento, você deve criar o objectStore necessário para a versão do banco:</span></p> + +<pre class="brush:js;">// Este evento é implementado somente em navegadores mais recentes +request.onupgradeneeded = function(event) { + var db = event.target.result; + + // cria um objectStore para esse banco + var objectStore = db.createObjectStore("nome", { keyPath: "minhaChave" }); +};</pre> + +<p>Neste caso, o banco já terá objectStores de suas versões anteriores, então você não terá que criar esses objectStores de novo. Você somente precisará criar um novo objectStore qualquer, ou deletar objectStores da versão anterior que não serão utilizados. Se você precisa mudar um objectStore existente (mudar o <code>keyPath, por exemplo</code>), então você precisa deletar o objectStore antigo e criá-lo novamente com as novas opções. (Note que isso irá deletar a informação no objectStore! Se você precisa salvar a informação, você deve ler isso e salvá-lo em algum lugar antes de atualizar o banco.)</p> + +<p>Blink/Webkit suporta a versão atual da especificação, nas versões do Chrome 23+ e Opera 17+; IE10+ também suporta. Outros motores e versões antigas não implementam a versão atual da especificação e não suportam a assinatura <code>indexedDB.open(name, version).onupgradeneeded</code> ainda. Para mais informação sobre como atualizar a versão do banco em Webkit/Blink, veja <a href="/en/IndexedDB/IDBDatabase#setVersion()_.0A.0ADeprecated" title="https://developer.mozilla.org/en/IndexedDB/IDBDatabase#setVersion()_.0A.0ADeprecated">IDBDatabase reference article</a>.</p> + +<h3 id="Estruturando_o_banco">Estruturando o banco</h3> + +<p>Agora a estrutura do banco. IndexedDB usa "armazens de objetos" em vez de tabelas, e um único banco de dados pode conter qualquer número de "armazem de objetos". Sempre que um valor é armazenado num objectStore, ele é associado a uma chave. Existe várias maneiras diferentes de uma chave ser mostrada, dependendo do que o objectStore usa, um <a href="/en/IndexedDB#gloss_key_path" title="https://developer.mozilla.org/en/IndexedDB#gloss_key_path">key path</a> ou <a href="/en/IndexedDB#gloss_key_generator" title="en/IndexedDB#gloss key generator">key generator</a>.</p> + +<p>A tabela abaixo mostra as direfentes chaves suportadas:</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Key Path (<code>keyPath</code>)</th> + <th scope="col">Key Generator (<code>autoIncrement</code>)</th> + <th scope="col">Description</th> + </tr> + </thead> + <tbody> + <tr> + <td>Não</td> + <td>Não</td> + <td>Este objectStore pode ter qualquer tipo de valor primitivo como número ou string. Você deve suprir uma chave separada sempre que adicionar um novo valor.</td> + </tr> + <tr> + <td>Sim</td> + <td>Não</td> + <td>Este objectStore pode simplesmente armazenar objetos JavaScript. O objeto deve ter uma propriedade com o mesmo nome do key path.</td> + </tr> + <tr> + <td>Não</td> + <td>Sim</td> + <td>Este objectStore pode possuir qualquer tipo de valor. A chave é gerada para você, automaticamente, ou você pode suprir uma chave separada, caso utilize uma chave específica.</td> + </tr> + <tr> + <td>Sim</td> + <td>Sim</td> + <td>Este objectStore suporta somente objetos JavaScript. Normalmente uma chave é gerada e o valor dela é armazenado no objeto em uma propriedade com o mesmo nome da key path. Portanto, se a propriedade já existe, o valor dela será usado como chave, em vez do valor gerado.</td> + </tr> + </tbody> +</table> + +<p>Você também pode criar índices em qualquer objectStore. Um indice deixa você olhar os valores armazenados no objectStore usando o valor de uma propriedade do objectStore, em vez de sua chave.</p> + +<p>Adicionalmente, indices tem a habilidade de forçar restrições simples nos dados armazenados. Setando uma flag única quando criar o índice, reforça que dois objetos são armazenados contendo o mesmo valor para o key path do índice. Então, por exemplo, se você tem um objeto armazenado que tem um conjunto de pessoas, e você quer ter certeza que ninguém tera o mesmo e-mail, você pode usar um índice com flag única para forçar isso.</p> + +<p>Isso soa meio confuso, mas este exemplo pode iluminar o conceito. Primeiro, vamos definir alguns dados a serem usados no exemplo:</p> + +<pre class="brush: js">// Isso é o que os dados de nossos clientes será. +const DadosClientes = [ + { ssn: "444-44-4444", nome: "Bill", idade: 35, email: "bill@company.com" }, + { ssn: "555-55-5555", nome: "Donna", idade: 32, email: "donna@home.org" } +]; +</pre> + +<p>Agora vamos ver ccomo criar um IndexedDB para armazenar nossos dados:</p> + +<pre class="brush: js">const dbName = "clientes"; + +var request = indexedDB.open(dbName, 2); + +request.onerror = function(event) { + // Tratar erros. +}; +request.onupgradeneeded = function(event) { + var db = event.target.result; + + // Cria um objectStore para conter a informação sobre nossos clientes. Nós vamos + // usar "ssn" como key path porque sabemos que é único; + var objectStore = db.createObjectStore("clientes", { keyPath: "ssn" }); + + // Cria um índice para buscar clientes pelo nome. Podemos ter nomes + // duplicados, então não podemos usar como índice único. + objectStore.createIndex("nome", "nome", { unique: false }); + + // Cria um índice para buscar clientes por email. Queremos ter certeza + // que não teremos 2 clientes com o mesmo e-mail; + objectStore.createIndex("email", "email", { unique: true }); + + // Usando transação oncomplete para afirmar que a criação do objectStore + // é terminada antes de adicionar algum dado nele. + objectStore.transaction.oncomplete = function(event) { + // Armazenando valores no novo objectStore. + var clientesObjectStore = db.transaction("clientes", "readwrite").objectStore("clientes"); + for (var i in DadosClientes) { + clientesObjectStore.add(DadosClientes[i]); + } + } +}; +</pre> + +<p>Como falamos antes, <code>onupgradeneeded</code> é o único lugar onde você pode alterar a estrutura do banco. Nele você pode criar e deletar objectStores e construir ou remover índices.</p> + +<div>Armazens de objetos são criados com uma única chamada de <code>createObjectStore()</code>. O método pega o nome do armazem e um objeto parâmetro. Mesmo que o objeto parâmetro seja opcional, ele é muito importante porque ele deixa você definir propriedades importantes e ajustar tipos de dados que você quer criar. No nosso caso, nós obtemos um objectStore chamado "clientes" e definimos um <code>keyPath</code>, que é a propriedade que faz um objeto individual ser único no banco. Essa propriedade, nesse exemplo, é "ssn", que simboliza o cpf (social security number), que é único. O "ssn" deve ser apresentado em cada objeto armazenado no <code>objectStore</code>. </div> + +<p>Nós também criamos um índice chamado "nome" ligado à propriedade <code>nome</code>. Assim como o <code>createObjectStore()</code>, o <code>createIndex()</code> tem um parâmetro opcional <code>options</code> que cuida do tipo de índice que você quer criar. Adicionando objetos que não tem a propriedade <code>nome</code> terá sucesso, porém esses objetos não aparecerão no índice "nome".</p> + +<p>Nós podemos obter os objetos de clientes armazenados usando os <code>ssn</code> da objectStore diretamente, ou usando os nomes usados no índice. Para aprender como isso é feito, veja a seção <a href="#Using_an_index" title="Using IndexedDB#Using an index">usando um índice</a>.</p> + +<h3 id="Usando_um_key_generator">Usando um key generator</h3> + +<p>Setando uma flag <code>autoIncrement </code>ao criar o objectStore habilitará o key generator. Por padrão ele não é setado.</p> + +<p>Com o key generator, a chave será gerada automaticamente quando você adicionar algum valor no objectStore. O atual número do key generator é sempre setado 1 quando a primeira key generator do objectStore é criada. Basicamente a próxima chave recebe o incremento de 1. O número atual da key generator nunca decresce, a não ser se alguma operação do banco for revertida, como numa transação abortada, por exemplo. No entanto, deletar um registro ou limpar todos os registros nunca afeta o key generator dos objectStores.</p> + +<p>Nós podemos criar outro objectStore com o key generator como abaixo:</p> + +<pre class="brush: js">// Abrindo o indexedDB. +var request = indexedDB.open(dbName, 3); + +request.onupgradeneeded = function (event) { + + var db = event.target.result; + + // Criando outro objeto chamado "names" com o autoIncrement setado. + var objStore = db.createObjectStore("names", { autoIncrement : true }); + + // Porque "names" tem o the key generator, a chave para o nome é gerada automaticamente. + // Os registros adicionados serão assim: + // key : 1 => value : "Bill" + // key : 2 => value : "Donna" + for (var i in DadosClientes) { + objStore.add(DadosClientes[i].nome); + } +}</pre> + +<p>Para mais detalhes veja <a href="http://www.w3.org/TR/IndexedDB/#key-generator-concept">"W3C Key Generators"</a>.</p> + +<h2 id="Adicionando_obtendo_e_removendo_dados">Adicionando, obtendo e removendo dados</h2> + +<p>Antes de fazer qualquer coisa em um novo banco, você precisa iniciar uma transação. Transações estão no objeto database, e você tem que especificar qual objectStore você quer na transaction. Uma vez que você está dentro da transação, você pode acessar os objectStores com seus dados e fazer os requests. Depois, você precisa decidir se você vai fazer mudanças no banco ou se você simplesmente quer ler esses dados. Transações tem três modos disponíveis: <code>readonly</code>, <code>readwrite</code>, and <code>versionchange</code>.</p> + +<p>Para mudar o "schema" ou estrutura do banco — o que envolve criar ou deletar objectStores ou índices — a transação deve ser em modo <code>versionchange</code>. Esta transação é aberta chamando o método {{domxref("IDBFactory.open")}} especificando a <code>version.</code> (Em navegadores com WebKit que não tem a ultima especificação implementada, o método {{domxref("IDBFactory.open")}} tem apenas um parâmetro, o <code>nome</code> do banco; então você deve chamar {{domxref("IDBVersionChangeRequest.setVersion")}} para estabelecer uma transação <code>versionchange</code>.)</p> + +<p>Para ler os registros de um objectStore existente, a transação pode ser tanto<code> readonly</code> quanto <code>readwrite</code>. Para fazer mudanças em um objectStore existente, a transação deve ser em modo <code>readwrite</code>. Você abre essas transações usando {{domxref("IDBDatabase.transaction")}}. O método aceita dois parâmetros: o <code>storeNames</code> (o escopo, definido como um array de objectStores que você quer acessar) e o <code>modo</code> (<code>readonly</code> or <code>readwrite</code>) da transação. O método retorna o objeto detransação contendo o método {{domxref("IDBIndex.objectStore")}}, que você pode usar para acessar seu objectStore. Por padrão, quando nenhum modo é especificado, a transação é aberta no modo <code>readonly</code>.</p> + +<p>Você pode deixar o acesso aos dados mais rápido usando o escopo correto e o modo correto de transação. Aqui vai algumas dicas:</p> + +<ul> + <li>Quando definir o escopo, especifique apenas os objectStores que você precisa. Desse jeito você pode rodar multiplas transações sem que uma sobreponha a outra.</li> + <li>Somente especifique uma transação <code>readwrite</code> quando necessário. Você pode rodar várias transações <code>readonly</code> com escopos sobreposts, mas você pode ter somente uma transação <code>readwrite</code> por objectStore. Para aprender mais sobre <dfn><a href="/en-US/docs/IndexedDB/Basic_Concepts_Behind_IndexedDB#Database">transactions</a></dfn> veja <a href="/en-US/docs/IndexedDB/Basic_Concepts_Behind_IndexedDB">Basic Concepts</a>.</li> +</ul> + +<h3 id="Adicionando_dados_no_banco">Adicionando dados no banco</h3> + +<p>Se você acabou de criar o banco, então você provavelmente quer escrever algo nele. Veja abaixo:</p> + +<pre class="brush:js;">var transaction = db.transaction(["clientes"], "readwrite"); +// Nota: Implementações mais antigas usam uma versão IDBTransaction.READ_WRITE antiga em vez de "readwrite". +// Então, para suportar versões antigas, escreva: +// var transaction = db.transaction(["clientes"], IDBTransaction.READ_WRITE);</pre> + +<p>A função <code>transaction()</code> tem dois argumentos (opcionais) e retorna um objeto de transação. O primeiro argumento é uma lista de objectStores que serão trabalhados na transação. Você pode passar um array vazio se você quer uma transação com todos os objectStores, mas não faça isso pois a especificação diz que um array vazio pode gerar um erro InvalidAccessError. Se você não especificar nada no segundo parâmetro, você tem uma transação read-only. Se você quer escrever no banco, use <code>"readwrite"</code>.</p> + +<p>Agora que você tem uma transação, você precisa entender seu tempo de uso. Transações são amarradas a um evento. Se você faz uma transação fora de um evento, ela ficará inativa. A única maneira de manter uma transação ativa é fazer um request nela. Quando o request acabar você terá a oportunidade de extender a transação durante o callback. Se você tentar extender uma transação dentro de um evento, então ela tornará inativa. Se existir requests pendentes, a transação continua ativa. O tempo de vida de uma transação é realmente simples mas deve ser usada em um curto espaço de tempo. Outros exemplos poderão ajudá-lo. Se você começar a ver<code> TRANSACTION_INACTIVE_ERR</code> error então você está fazendo algo errado.</p> + +<p>Transações podem receber eventos DOM de três tipos diferentes: <code>error</code>, <code>abort</code>, e <code>complete</code>. Nós falamos sobre o <code>error</code>, ou seja, a transação recebe um error sempre que o request gerar erro. Um ponto mais sutil é que o comportamento padrão de um erro é abortar a transação na qual ele estava. A menos que você manipule o erro chamando <code>preventDefault()</code> e fazendo algo depois, a transaçaõ inteira será desfeita. Este design força você a pensar sobre manipulação de erros, mas você pode sempre adicionar um manipulador de todos os erros se a manipulação separada estiver complicada. Se você não tratar o erro ou chamar <code>abort()</code> na transação, então a transação é desfeita (roll back) e o evento <code>abort</code> é chamado. Por outro lado, depois de todo request completado, você tem um evento <code>complete</code>. Se você fazer várias operações no banco, então seguir as operações de transações pode ser um caminho a seguir.</p> + +<p>Agora que você tem uma transação, você precisará obter um objectStore dela. Transações somente deixam você obter um objectStore citado na transação. Então você pode adicionar os dados que precisa.</p> + +<pre class="brush: js">// Faz algo após a inserção dos dados. +transaction.oncomplete = function(event) { + alert("Pronto!"); +}; + +transaction.onerror = function(event) { + // Não esquecer de tratar os erros! +}; + +var objectStore = transaction.objectStore("clientes"); +for (var i in DadosClientes) { + var request = objectStore.add(DadosClientes[i]); + request.onsuccess = function(event) { + // event.target.result == DadosClientes[i].ssn; + }; +}</pre> + +<p>O <code>result</code> de um request gerado de uma chamada de <code>add()</code> é a chave do valor que foi adicionado. Então neste caso, ele deve ser igual ao valor do <code>ssn</code> do objeto que foi adicionado, desde que o objeto use o <code>ssn</code> como key path. Note que a função <code>add()</code> não deixa nenhum objeto ser adicionado com a mesma chave. Se você está tentando modificar um registro existente, você deve usar o <code>put()</code>, como explica a seção {{ anch("Updating an entry in the database") }}.</p> + +<h3 id="Removendo_dados_do_banco">Removendo dados do banco</h3> + +<p>Para remoção o código é parecido:</p> + +<pre class="brush: js">var request = db.transaction(["clientes"], "readwrite") + .objectStore("clientes") + .delete("444-44-4444"); +request.onsuccess = function(event) { + // Pronto! +};</pre> + +<h3 id="Obtendo_dados_do_banco">Obtendo dados do banco</h3> + +<p>Agora que o banco tem algumas informações nele, você pode obtê-las de diferentes maneiras. Primeiro, um <code>get()</code> simples. Você precisa informar a chave do valor a ser obtido:</p> + +<pre class="brush: js">var transaction = db.transaction(["clientes"]); +var objectStore = transaction.objectStore("clientes"); +var request = objectStore.get("444-44-4444"); +request.onerror = function(event) { + // Tratar erro! +}; +request.onsuccess = function(event) { + // Fazer algo com request.result! + alert("O nome do SSN 444-44-4444 é " + request.result.name); +};</pre> + +<p>Veja agora de maneira resumida:</p> + +<pre class="brush: js">db.transaction("clientes").objectStore("clientes").get("444-44-4444").onsuccess = function(event) { + alert("O nome do SSN 444-44-4444 é " + request.result.name); +};</pre> + +<p>Viu como funciona? Desde que exista um objectStore, você pode evitar passar uma lista de objectStores que precisa na transação e passar apenas o nome como string. Você também pode ler do banco, apenas, então não precisará de uma transação <code>"readwrite".</code> Chamando <code>transaction()</code> com nenhum modo especificado, você terá uma transação <code>"readonly"</code>. Outra consideração é que você não necessita salvar o request em uma variável. Desde que o evento DOM tenha o target que você precisará para obter a propriedade <code>result</code>.</p> + +<div class="note"> +<p><strong>Note</strong>: Você pode deixar o acesso aos dados mais rápido limitando o escopo e o modo de transação. Veja algumas dicas:</p> + +<ul> + <li> + <p>Quando definir o <a href="#scope">escopo</a>, especifique somente os objectStores que vai precisar. Assim você pode rodar multiplas transações sem sopreposições.</p> + </li> + <li> + <p>Utilize uma transação <code>readwrite</code> somente quando necessário. Você pode rodar várias transações <code>readonly</code> simultâneas, mas apenas uma transação <code>readwrite</code> por objectStore. Para aprender mais sobre isso veja o artigo <a href="/en-US/docs/IndexedDB/Basic_Concepts_Behind_IndexedDB#gloss_transaction"><dfn>transactions</dfn> in the Basic Concepts</a>.</p> + </li> +</ul> +</div> + +<h3 id="Atualizando_um_registro_no_banco">Atualizando um registro no banco</h3> + +<p>Agora que obtemos algum dado, atualizá-ls é inserí-los novamente no IndexedDB é bem simples. Vamos atualizar o exemplo anterior:</p> + +<pre class="brush: js">var objectStore = db.transaction(["clientes"], "readwrite").objectStore("clientes"); +var request = objectStore.get("444-44-4444"); +request.onerror = function(event) { + // Tratar erro +}; +request.onsuccess = function(event) { + // Obter os valores antigos + var data = request.result; + + // atualizar algum dado + data.age = 42; + + // Atulizar esse dado no banco + var requestUpdate = objectStore.put(data); + requestUpdate.onerror = function(event) { + // Tratar erro + }; + requestUpdate.onsuccess = function(event) { + // Sucesso na atualização \o/ + }; +};</pre> + +<p>Criamos uma <code>objectStore</code> e obtemos um cliente dele, identificado pelo ssn (<code>444-44-4444</code>). Nós atualizamos o objeto, passando-o como parâmetro de um método put de outro request (<code>requestUpdate</code>) sobrescrevendo o valor antigo.</p> + +<div class="note"> +<p><strong>Note</strong> que neste caso nós temos que especificar a transação <code>readwrite</code> porque nós queremos escrever no banco, não somente ler os dados dele.</p> +</div> + +<h3 id="Usando_um_cursor">Usando um cursor</h3> + +<p>Ao usar o método <code>get()</code> você precisa saber a chave do objeto que deseja obter. Se você quer passear entre todos os valores do seu objectStore, então você pode usar um cursor. Veja:</p> + +<pre class="brush: js">var objectStore = db.transaction("cliente").objectStore("cliente"); + +objectStore.openCursor().onsuccess = function(event) { + var cursor = event.target.result; + if (cursor) { + alert("O nome do SSN " + cursor.key + " é " + cursor.value.name); + cursor.continue(); + } + else { + alert("Não existe mais registros!"); + } +};</pre> + +<p><code>A função openCursor()</code> tem vários argumentos. Primeiro, você pode limitar o número de itens obtidos usando uma chave que veremos logo abaixo. Segundo, você pode especificar a direção que deseja iterar. No exemplo acima, nós estamos iterando em todos os objetos em ordem ascendente. O callback de sucesso para cursor é um pouco especial. O objeto cursor já é o <code>result</code> do request (acima nós usamos <code>event.target.result</code>). Então a chave atual e o valor pode ser encontrado na propriedade <code>key</code> e <code>value</code> do objeto cursor. Se você quer manter adiante, então você usa o método <code>continue()</code>. Quando você chegar ao fim dos dados (ou se não existem registros encontrados no <code>openCursor()</code>) você ainda tem um callback de sucesso, mas a propriedade <code>result</code> fica <code>undefined</code>.</p> + +<p>Um padrão comum para cursores é obter todos os objetos em um objectStore e adicioná-los a um array como este:</p> + +<pre class="brush: js">var clientes = []; + +objectStore.openCursor().onsuccess = function(event) { + var cursor = event.target.result; + if (cursor) { + clientes.push(cursor.value); + cursor.continue(); + } + else { + alert("Todos os clientes: " + clientes); + } +};</pre> + +<div class="note"> +<p>Note: Mozilla também implementou o método <code>getAll()</code> para ser usado nesse caso (e <code>getAllKeys()</code>, que está atualmente dentro da preferência do <code>dom.indexedDB.experimental</code> em about:config). Estes métodos não são parte do padrão IndexedDB, então eles podem desaparecer no futuro. Nós adicionamos porque achamos útil. O código abaixo faz o mesmo que o código acima:</p> + +<pre class="brush: js">objectStore.getAll().onsuccess = function(event) { + alert("Todos os clientes: " + event.target.result); +};</pre> + +<p>Existe um custo de performance associado com a propriedade <code>value</code> do cursor, porque o objeto é criado de forma lenta. Quando você usa <code>getAll()</code> por exemplo, Gecko deve criar todos os objetos de uma vez. Se você está somente interessado em cada chave, é muito melhor usar o cursor do que usar o <code>getAll()</code>. Se você está tentando obter um array de todos os objetos, então é melhor usar o <code>getAll()</code>.</p> +</div> + +<h3 id="Usando_um_índice">Usando um índice</h3> + +<p>Armazenar dados de um cliente usando o SSN como chave é lógico pois o SSN identifica o cliente de forma única. Se você precisa obter um cliente pelo seu nome, portanto, você precisará iterar todos os registros no banco e comparar os nomes até achar o que você procura. Buscar dessa maneira é algo lento, então criamos um índice.</p> + +<pre class="brush: js">var index = objectStore.index("nome"); +index.get("John").onsuccess = function(event) { + alert("O SSN de John é " + event.target.result.ssn); +};</pre> + +<p>O cursor "nome" não é único, então pode existir mais de um registro com o <code>nome</code> igual a <code>"John"</code>. Neste caso você sempre obtem o registro com a chave de menor valor.</p> + +<p>Se você precisa acessar todos os registros retornados, você pode usar um cursor. Você pode abrir dois tipos de cursores. Um cursor normal mapeia o índice ao objeto na objectStore. Uma cursor-chave mapeia o a propriedade índice à chave usada para armazenar o objeto. As diferenças são ilustradas abaixo:</p> + +<pre class="brush: js">// Usando um cursor normal para obter todos os objetos +index.openCursor().onsuccess = function(event) { + var cursor = event.target.result; + if (cursor) { + // cursor.key é um nome, como "Bill", e cursor.value é o objeto inteiro. + alert("Nome: " + cursor.key + ", SSN: " + cursor.value.ssn + ", email: " + cursor.value.email); + cursor.continue(); + } +}; + +// Usando um cursor-chave para obter todos os objetos +index.openKeyCursor().onsuccess = function(event) { + var cursor = event.target.result; + if (cursor) { + // cursor.key é o nome, como "Bill", e cursor.value é o SSN (chave). + // Não tem como obter o resto do objeto + alert("Nome: " + cursor.key + ", SSN: " + cursor.value); + cursor.continue(); + } +};</pre> + +<h3 id="Especificando_o_número_e_a_direção_dos_cursores">Especificando o número e a direção dos cursores</h3> + +<p>Se você gostaria de limitar o número de valores retornados pelo cursor, você pode usar um objeto <code>IDBKeyRange</code> e passar isso como o primeiro argumento ao <code>openCursor()</code> ou <code>openKeyCursor()</code>. Você pode fazer um key range que permite um único valor, ou valores acima ou abaixo do especificado. O limite pode ser fechado (o key range inclui os valores dados) ou aberto (o key range não inclue os valores dados). Veja como funciona:</p> + +<pre class="brush: js">// Somente se for igual "Donna" +var singleKeyRange = IDBKeyRange.only("Donna"); + +// Combinações menores que "Bill", incluindo "Bill" +var lowerBoundKeyRange = IDBKeyRange.lowerBound("Bill"); + +// Combinações menores que "Bill", sem incluir "Bill" +var lowerBoundOpenKeyRange = IDBKeyRange.lowerBound("Bill", true); + +// Combinações maiores que Donna, não incluindo "Donna" +var upperBoundOpenKeyRange = IDBKeyRange.upperBound("Donna", true); + +// Combinações entre "Bill" e "Donna", sem incluir "Donna" +var boundKeyRange = IDBKeyRange.bound("Bill", "Donna", false, true); + +// Para usar qualquer um desses key ranges, basta passar como primeiro parâmetro de openCursor()/openKeyCursor() +index.openCursor(boundKeyRange).onsuccess = function(event) { + var cursor = event.target.result; + if (cursor) { + // Faz algo com o que encontrar + cursor.continue(); + } +};</pre> + +<p>As vezes você pode querer iterar em ordem decrescente, em vez de crescente, alterando o segundo parâmetro de <code>openCursor()</code>:</p> + +<pre class="brush: js">objectStore.openCursor(boundKeyRange, "prev").onsuccess = function(event) { + var cursor = event.target.result; + if (cursor) { + // Prev indica ordem decrescente + cursor.continue(); + } +};</pre> + +<p>Se você apenas quer especificar a ordem sem key range, é só passar null no primeiro parâmetro:</p> + +<pre class="brush: js">objectStore.openCursor(null, "prev").onsuccess = function(event) { + var cursor = event.target.result; + if (cursor) { + // Faça algo com os resultados. + cursor.continue(); + } +};</pre> + +<p>Uma vez que o índice "nome" não é único, pode existir várias entradas onde o <code>nome</code> é o mesmo. Isso não acontece com objectStores porque a chave deve ser sempre única. Se você deseja filtrar valores duplicados numa iteração do cursor, você pode passar <code>nextunique</code> (ou <code>prevunique</code> se quiser decrescer) como parâmetro de direção. Quando <code>nextunique</code> ou <code>prevunique</code> é usado, o registro com menor chave é retornado.</p> + +<pre class="brush: js">index.openKeyCursor(null, "nextunique").onsuccess = function(event) { + var cursor = event.target.result; + if (cursor) { + // Faça algo com os registros. + cursor.continue(); + } +};</pre> + +<p>Veja "<a href="https://developer.mozilla.org/en-US/docs/Web/API/IDBCursor?redirectlocale=en-US&redirectslug=IndexedDB%2FIDBCursor#Constants">IDBCursor Constants</a>" para parâmetros válidos.</p> + +<h2 id="Mudança_de_versão_quando_a_web_app_está_aberta_em_outra_aba.">Mudança de versão quando a web app está aberta em outra aba.</h2> + +<p>Quando sua web app muda a versão você precisa considerar o que vai acontecer se o usuário está na versão antiga em uma aba, e carrega a versão nova na outra. Quando você chamar o <code>open()</code> com a versão mais nova, um evento <code>onblocked</code> é chamado até que a aba da versão antiga seja fechada ou recarregada. Veja abaixo:</p> + +<pre class="brush: js">var openReq = mozIndexedDB.open("DBteste", 2); + +openReq.onblocked = function(event) { + // Se existe outra aba com a versão antiga + alert("Existe uma versão antiga da web app aberta em outra aba, feche-a por favor!"); +}; + +openReq.onupgradeneeded = function(event) { + // Se estiver tudo fechado, então faça as devidas alterações + db.createObjectStore(/* ... */); + useDatabase(db); +} + +openReq.onsuccess = function(event) { + var db = event.target.result; + useDatabase(db); + return; +} + +function useDatabase(db) { + // Esteja certo de que adicionou um evento para notificar se a página muda a versão + // Nós devemos fechar o banco. Isso permite à outra página ser atualizada + // Se você não fizer isso a atualização não acontecerá até fechar as abas. + db.onversionchange = function(event) { + db.close(); + alert("Uma nova versão desta web app está pronta. Atualiza, por favor!"); + }; + + // Fazer algo com os bancos +} +</pre> + +<h2 id="Segurança">Segurança</h2> + +<p>IndexedDB usa o princípio de mesma origem, o que significa que o banco só será acessado pelo site que o criou.</p> + +<p>É importante notar que o IndexedDB não funciona para conteúdo carregado em um frame de outro site (seja {{ HTMLElement("frame") }} ou {{ HTMLElement("iframe") }}. Esta é uma política de segurança e privacidade análoga ao bloqueio de cookies de terceiros. Para mais detalhes, veja {{ bug(595307) }}.</p> + +<h2 id="Alerta_sobre_fechar_o_navegador">Alerta sobre fechar o navegador</h2> + +<p>Quando o navegador é fechado, qualquer transação pendente no IndexedDB será abortada (silenciosamente) — ele não vai completar, nem chamar o evento de erro. <span id="result_box" lang="pt"><span class="hps">Uma vez que o</span> <span class="hps">usuário pode</span> <span class="hps">sair do navegador</span><span>, em qualquer momento</span><span>, isto significa que</span> <span class="hps">você não pode</span> <span class="hps">confiar em qualquer</span> <span class="hps">transação específica</span> <span class="hps">para completar</span> <span class="hps">ou</span> <span class="hps">para saber que</span> <span class="hps">ela não foi concluída</span><span>.</span></span> Existem várias implicações nesse comportamento.</p> + +<p><span id="result_box" lang="pt"><span class="hps">Primeiro, você deve</span> <span class="hps">ter o cuidado de</span> <span class="hps">sempre deixar</span> <span class="hps">seu banco de dados</span> <span class="hps">em um estado consistente</span><span>, no final de</span> <span class="hps">cada transação.</span> <span class="hps">Por exemplo, suponha</span> <span class="hps">que você está usando</span> <span class="hps">IndexedDB</span> <span class="hps">para armazenar</span> <span class="hps">uma lista de</span> <span class="hps">itens que</span> <span class="hps">permitem ao usuário</span> <span class="hps">editar.</span> <span class="hps">Você</span> <span class="hps">salvar a lista</span> <span class="hps">após</span> <span class="hps">a edição</span><span>, limpando o</span> <span class="hps">armazenamento de objetos</span> <span class="hps">e</span><span>, em seguida,</span> <span class="hps">escrever a</span> <span class="hps">nova lista.</span> <span class="hps">Se você</span> <span class="hps">limpar o</span> <span class="hps">armazenamento de objetos</span> <span class="hps">em uma transação</span> <span class="hps">e escrever</span> <span class="hps">a nova lista</span> <span class="hps">em outra transação</span><span>, há um</span> <span class="hps">perigo de que o</span> <span class="hps">navegador irá</span> <span class="hps">fechar</span> <span class="hps">após a</span> limpeza de dados e <span class="hps">antes da</span> <span class="hps">gravação</span><span>,</span> <span class="hps">deixando-o com</span> <span class="hps">um banco de dados</span> <span class="hps">vazio.</span> <span class="hps">Para evitar isso,</span> <span class="hps">você deve combinar</span> tanto a limpeza quanto a <span class="hps">gravação</span> <span class="hps">em</span> <span class="hps">uma única transação.</span></span></p> + +<p><span id="result_box" lang="pt"><span class="hps">Em segundo lugar,</span> <span class="hps">você nunca deve</span> <span class="hps">amarrar</span> <span class="hps">as operações</span> <span class="hps">de banco de dados</span> ao evento unload<span class="hps">.</span> <span class="hps">Se o evento</span> <span class="hps">unload</span> <span class="hps">é acionado</span> <span class="hps">pelo fechamento</span> <span class="hps">do navegador</span><span>,</span> <span class="hps">todas as transações</span> <span class="hps">criadas</span> <span class="hps">no unload</span> <span class="hps">nunca</span> <span class="hps">serão concluídas</span><span>.</span> <span class="hps">Uma abordagem</span> <span class="hps">intuitiva para</span> <span class="hps">manter</span> <span class="hps">algumas informações</span> <span class="hps">em sessões do navegador</span> <span class="hps">é lê-la</span> <span class="hps">a partir do</span> <span class="hps">banco de dados</span> <span class="hps">quando o navegador</span> <span class="hps">(ou</span> <span class="hps">uma determinada página</span><span>)</span> é<span class="hps"> aberta,</span> <span class="hps">atualizá-la</span> <span class="hps">assim que</span> <span class="hps">o usuário interagir</span> <span class="hps">com o navegador,</span> <span class="hps">e depois</span> <span class="hps">salvá-lo para</span> <span class="hps">o banco de dados</span> <span class="hps">quando o navegador</span> <span class="atn hps">(</span><span class="hps">ou página)</span> <span class="hps">será fechada.</span> <span class="hps">No entanto, isso</span> <span class="hps">não vai funcionar.</span> <span class="hps">As transações</span> <span class="hps">de banco de dados</span> <span class="hps">será criado</span> <span class="hps">no unload</span><span>, mas como elas</span> <span class="hps">são assíncronas</span>, <span class="hps">serão abortada</span>s <span class="hps">antes que eles possam</span> <span class="hps">executar.</span></span></p> + +<p>De fato, não existe uma maneira de garantir que as transações no IndexedDBserão completadas, mesmo com o fechamento padrão do navegador. Ver {{ bug(870645) }}.</p> + +<h2 id="Full_IndexedDB_example" name="Full_IndexedDB_example">Exemplo de IndexedDB</h2> + +<h3 id="HTML">HTML</h3> + +<pre class="brush: html"><script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script> + + <h1>IndexedDB Demo: storing blobs, e-publication example</h1> + <div class="note"> + <p> + Works and tested with: + </p> + <div id="compat"> + </div> + </div> + + <div id="msg"> + </div> + + <form id="register-form"> + <table> + <tbody> + <tr> + <td> + <label for="pub-title" class="required"> + Title: + </label> + </td> + <td> + <input type="text" id="pub-title" name="pub-title" /> + </td> + </tr> + <tr> + <td> + <label for="pub-biblioid" class="required"> + Bibliographic ID:<br/> + <span class="note">(ISBN, ISSN, etc.)</span> + </label> + </td> + <td> + <input type="text" id="pub-biblioid" name="pub-biblioid"/> + </td> + </tr> + <tr> + <td> + <label for="pub-year"> + Year: + </label> + </td> + <td> + <input type="number" id="pub-year" name="pub-year" /> + </td> + </tr> + </tbody> + <tbody> + <tr> + <td> + <label for="pub-file"> + File image: + </label> + </td> + <td> + <input type="file" id="pub-file"/> + </td> + </tr> + <tr> + <td> + <label for="pub-file-url"> + Online-file image URL:<br/> + <span class="note">(same origin URL)</span> + </label> + </td> + <td> + <input type="text" id="pub-file-url" name="pub-file-url"/> + </td> + </tr> + </tbody> + </table> + + <div class="button-pane"> + <input type="button" id="add-button" value="Add Publication" /> + <input type="reset" id="register-form-reset"/> + </div> + </form> + + <form id="delete-form"> + <table> + <tbody> + <tr> + <td> + <label for="pub-biblioid-to-delete"> + Bibliographic ID:<br/> + <span class="note">(ISBN, ISSN, etc.)</span> + </label> + </td> + <td> + <input type="text" id="pub-biblioid-to-delete" + name="pub-biblioid-to-delete" /> + </td> + </tr> + <tr> + <td> + <label for="key-to-delete"> + Key:<br/> + <span class="note">(for example 1, 2, 3, etc.)</span> + </label> + </td> + <td> + <input type="text" id="key-to-delete" + name="key-to-delete" /> + </td> + </tr> + </tbody> + </table> + <div class="button-pane"> + <input type="button" id="delete-button" value="Delete Publication" /> + <input type="button" id="clear-store-button" + value="Clear the whole store" class="destructive" /> + </div> + </form> + + <form id="search-form"> + <div class="button-pane"> + <input type="button" id="search-list-button" + value="List database content" /> + </div> + </form> + + <div> + <div id="pub-msg"> + </div> + <div id="pub-viewer"> + </div> + <ul id="pub-list"> + </ul> + </div> +</pre> + +<h3 id="CSS_Content">CSS Content</h3> + +<pre class="brush: css">body { + font-size: 0.8em; + font-family: Sans-Serif; +} + +form { + background-color: #cccccc; + border-radius: 0.3em; + display: inline-block; + margin-bottom: 0.5em; + padding: 1em; +} + +table { + border-collapse: collapse; +} + +input { + padding: 0.3em; + border-color: #cccccc; + border-radius: 0.3em; +} + +.required:after { + content: "*"; + color: red; +} + +.button-pane { + margin-top: 1em; +} + +#pub-viewer { + float: right; + width: 48%; + height: 20em; + border: solid #d092ff 0.1em; +} +#pub-viewer iframe { + width: 100%; + height: 100%; +} + +#pub-list { + width: 46%; + background-color: #eeeeee; + border-radius: 0.3em; +} +#pub-list li { + padding-top: 0.5em; + padding-bottom: 0.5em; + padding-right: 0.5em; +} + +#msg { + margin-bottom: 1em; +} + +.action-success { + padding: 0.5em; + color: #00d21e; + background-color: #eeeeee; + border-radius: 0.2em; +} + +.action-failure { + padding: 0.5em; + color: #ff1408; + background-color: #eeeeee; + border-radius: 0.2em; +} + +.note { + font-size: smaller; +} + +.destructive { + background-color: orange; +} +.destructive:hover { + background-color: #ff8000; +} +.destructive:active { + background-color: red; +} +</pre> + +<p> </p> + +<h3 id="JavaScript_Content">JavaScript Content</h3> + +<pre class="brush: js">(function () { + var COMPAT_ENVS = [ + ['Firefox', ">= 16.0"], + ['Google Chrome', + ">= 24.0 (you may need to get Google Chrome Canary), NO Blob storage support"] + ]; + var compat = $('#compat'); + compat.empty(); + compat.append('<ul id="compat-list"></ul>'); + COMPAT_ENVS.forEach(function(val, idx, array) { + $('#compat-list').append('<li>' + val[0] + ': ' + val[1] + '</li>'); + }); + + const DB_NAME = 'mdn-demo-indexeddb-epublications'; + const DB_VERSION = 1; // Use a long long for this value (don't use a float) + const DB_STORE_NAME = 'publications'; + + var db; + + // Used to keep track of which view is displayed to avoid uselessly reloading it + var current_view_pub_key; + + function openDb() { + console.log("openDb ..."); + var req = indexedDB.open(DB_NAME, DB_VERSION); + req.onsuccess = function (evt) { + // Better use "this" than "req" to get the result to avoid problems with + // garbage collection. + // db = req.result; + db = this.result; + console.log("openDb DONE"); + }; + req.onerror = function (evt) { + console.error("openDb:", evt.target.errorCode); + }; + + req.onupgradeneeded = function (evt) { + console.log("openDb.onupgradeneeded"); + var store = evt.currentTarget.result.createObjectStore( + DB_STORE_NAME, { keyPath: 'id', autoIncrement: true }); + + store.createIndex('biblioid', 'biblioid', { unique: true }); + store.createIndex('title', 'title', { unique: false }); + store.createIndex('year', 'year', { unique: false }); + }; + } + + /** + * @param {string} store_name + * @param {string} mode either "readonly" or "readwrite" + */ + function getObjectStore(store_name, mode) { + var tx = db.transaction(store_name, mode); + return tx.objectStore(store_name); + } + + function clearObjectStore(store_name) { + var store = getObjectStore(DB_STORE_NAME, 'readwrite'); + var req = store.clear(); + req.onsuccess = function(evt) { + displayActionSuccess("Store cleared"); + displayPubList(store); + }; + req.onerror = function (evt) { + console.error("clearObjectStore:", evt.target.errorCode); + displayActionFailure(this.error); + }; + } + + function getBlob(key, store, success_callback) { + var req = store.get(key); + req.onsuccess = function(evt) { + var value = evt.target.result; + if (value) + success_callback(value.blob); + }; + } + + /** + * @param {IDBObjectStore=} store + */ + function displayPubList(store) { + console.log("displayPubList"); + + if (typeof store == 'undefined') + store = getObjectStore(DB_STORE_NAME, 'readonly'); + + var pub_msg = $('#pub-msg'); + pub_msg.empty(); + var pub_list = $('#pub-list'); + pub_list.empty(); + // Resetting the iframe so that it doesn't display previous content + newViewerFrame(); + + var req; + req = store.count(); + // Requests are executed in the order in which they were made against the + // transaction, and their results are returned in the same order. + // Thus the count text below will be displayed before the actual pub list + // (not that it is algorithmically important in this case). + req.onsuccess = function(evt) { + pub_msg.append('<p>There are <strong>' + evt.target.result + + '</strong> record(s) in the object store.</p>'); + }; + req.onerror = function(evt) { + console.error("add error", this.error); + displayActionFailure(this.error); + }; + + var i = 0; + req = store.openCursor(); + req.onsuccess = function(evt) { + var cursor = evt.target.result; + + // If the cursor is pointing at something, ask for the data + if (cursor) { + console.log("displayPubList cursor:", cursor); + req = store.get(cursor.key); + req.onsuccess = function (evt) { + var value = evt.target.result; + var list_item = $('<li>' + + '[' + cursor.key + '] ' + + '(biblioid: ' + value.biblioid + ') ' + + value.title + + '</li>'); + if (value.year != null) + list_item.append(' - ' + value.year); + + if (value.hasOwnProperty('blob') && + typeof value.blob != 'undefined') { + var link = $('<a href="' + cursor.key + '">File</a>'); + link.on('click', function() { return false; }); + link.on('mouseenter', function(evt) { + setInViewer(evt.target.getAttribute('href')); }); + list_item.append(' / '); + list_item.append(link); + } else { + list_item.append(" / No attached file"); + } + pub_list.append(list_item); + }; + + // Move on to the next object in store + cursor.continue(); + + // This counter serves only to create distinct ids + i++; + } else { + console.log("No more entries"); + } + }; + } + + function newViewerFrame() { + var viewer = $('#pub-viewer'); + viewer.empty(); + var iframe = $('<iframe />'); + viewer.append(iframe); + return iframe; + } + + function setInViewer(key) { + console.log("setInViewer:", arguments); + key = Number(key); + if (key == current_view_pub_key) + return; + + current_view_pub_key = key; + + var store = getObjectStore(DB_STORE_NAME, 'readonly'); + getBlob(key, store, function(blob) { + console.log("setInViewer blob:", blob); + var iframe = newViewerFrame(); + + // It is not possible to set a direct link to the + // blob to provide a mean to directly download it. + if (blob.type == 'text/html') { + var reader = new FileReader(); + reader.onload = (function(evt) { + var html = evt.target.result; + iframe.load(function() { + $(this).contents().find('html').html(html); + }); + }); + reader.readAsText(blob); + } else if (blob.type.indexOf('image/') == 0) { + iframe.load(function() { + var img_id = 'image-' + key; + var img = $('<img id="' + img_id + '"/>'); + $(this).contents().find('body').html(img); + var obj_url = window.URL.createObjectURL(blob); + $(this).contents().find('#' + img_id).attr('src', obj_url); + window.URL.revokeObjectURL(obj_url); + }); + } else if (blob.type == 'application/pdf') { + $('*').css('cursor', 'wait'); + var obj_url = window.URL.createObjectURL(blob); + iframe.load(function() { + $('*').css('cursor', 'auto'); + }); + iframe.attr('src', obj_url); + window.URL.revokeObjectURL(obj_url); + } else { + iframe.load(function() { + $(this).contents().find('body').html("No view available"); + }); + } + + }); + } + + /** + * @param {string} biblioid + * @param {string} title + * @param {number} year + * @param {string} url the URL of the image to download and store in the local + * IndexedDB database. The resource behind this URL is subjected to the + * "Same origin policy", thus for this method to work, the URL must come from + * the same origin as the web site/app this code is deployed on. + */ + function addPublicationFromUrl(biblioid, title, year, url) { + console.log("addPublicationFromUrl:", arguments); + + var xhr = new XMLHttpRequest(); + xhr.open('GET', url, true); + // Setting the wanted responseType to "blob" + // http://www.w3.org/TR/XMLHttpRequest2/#the-response-attribute + xhr.responseType = 'blob'; + xhr.onload = function (evt) { + if (xhr.status == 200) { + console.log("Blob retrieved"); + var blob = xhr.response; + console.log("Blob:", blob); + addPublication(biblioid, title, year, blob); + } else { + console.error("addPublicationFromUrl error:", + xhr.responseText, xhr.status); + } + }; + xhr.send(); + + // We can't use jQuery here because as of jQuery 1.8.3 the new "blob" + // responseType is not handled. + // http://bugs.jquery.com/ticket/11461 + // http://bugs.jquery.com/ticket/7248 + // $.ajax({ + // url: url, + // type: 'GET', + // xhrFields: { responseType: 'blob' }, + // success: function(data, textStatus, jqXHR) { + // console.log("Blob retrieved"); + // console.log("Blob:", data); + // // addPublication(biblioid, title, year, data); + // }, + // error: function(jqXHR, textStatus, errorThrown) { + // console.error(errorThrown); + // displayActionFailure("Error during blob retrieval"); + // } + // }); + } + + /** + * @param {string} biblioid + * @param {string} title + * @param {number} year + * @param {Blob=} blob + */ + function addPublication(biblioid, title, year, blob) { + console.log("addPublication arguments:", arguments); + var obj = { biblioid: biblioid, title: title, year: year }; + if (typeof blob != 'undefined') + obj.blob = blob; + + var store = getObjectStore(DB_STORE_NAME, 'readwrite'); + var req; + try { + req = store.add(obj); + } catch (e) { + if (e.name == 'DataCloneError') + displayActionFailure("This engine doesn't know how to clone a Blob, " + + "use Firefox"); + throw e; + } + req.onsuccess = function (evt) { + console.log("Insertion in DB successful"); + displayActionSuccess(); + displayPubList(store); + }; + req.onerror = function() { + console.error("addPublication error", this.error); + displayActionFailure(this.error); + }; + } + + /** + * @param {string} biblioid + */ + function deletePublicationFromBib(biblioid) { + console.log("deletePublication:", arguments); + var store = getObjectStore(DB_STORE_NAME, 'readwrite'); + var req = store.index('biblioid'); + req.get(biblioid).onsuccess = function(evt) { + if (typeof evt.target.result == 'undefined') { + displayActionFailure("No matching record found"); + return; + } + deletePublication(evt.target.result.id, store); + }; + req.onerror = function (evt) { + console.error("deletePublicationFromBib:", evt.target.errorCode); + }; + } + + /** + * @param {number} key + * @param {IDBObjectStore=} store + */ + function deletePublication(key, store) { + console.log("deletePublication:", arguments); + + if (typeof store == 'undefined') + store = getObjectStore(DB_STORE_NAME, 'readwrite'); + + // As per spec http://www.w3.org/TR/IndexedDB/#object-store-deletion-operation + // the result of the Object Store Deletion Operation algorithm is + // undefined, so it's not possible to know if some records were actually + // deleted by looking at the request result. + var req = store.get(key); + req.onsuccess = function(evt) { + var record = evt.target.result; + console.log("record:", record); + if (typeof record == 'undefined') { + displayActionFailure("No matching record found"); + return; + } + // Warning: The exact same key used for creation needs to be passed for + // the deletion. If the key was a Number for creation, then it needs to + // be a Number for deletion. + req = store.delete(key); + req.onsuccess = function(evt) { + console.log("evt:", evt); + console.log("evt.target:", evt.target); + console.log("evt.target.result:", evt.target.result); + console.log("delete successful"); + displayActionSuccess("Deletion successful"); + displayPubList(store); + }; + req.onerror = function (evt) { + console.error("deletePublication:", evt.target.errorCode); + }; + }; + req.onerror = function (evt) { + console.error("deletePublication:", evt.target.errorCode); + }; + } + + function displayActionSuccess(msg) { + msg = typeof msg != 'undefined' ? "Success: " + msg : "Success"; + $('#msg').html('<span class="action-success">' + msg + '</span>'); + } + function displayActionFailure(msg) { + msg = typeof msg != 'undefined' ? "Failure: " + msg : "Failure"; + $('#msg').html('<span class="action-failure">' + msg + '</span>'); + } + function resetActionStatus() { + console.log("resetActionStatus ..."); + $('#msg').empty(); + console.log("resetActionStatus DONE"); + } + + function addEventListeners() { + console.log("addEventListeners"); + + $('#register-form-reset').click(function(evt) { + resetActionStatus(); + }); + + $('#add-button').click(function(evt) { + console.log("add ..."); + var title = $('#pub-title').val(); + var biblioid = $('#pub-biblioid').val(); + if (!title || !biblioid) { + displayActionFailure("Required field(s) missing"); + return; + } + var year = $('#pub-year').val(); + if (year != '') { + // Better use Number.isInteger if the engine has EcmaScript 6 + if (isNaN(year)) { + displayActionFailure("Invalid year"); + return; + } + year = Number(year); + } else { + year = null; + } + + var file_input = $('#pub-file'); + var selected_file = file_input.get(0).files[0]; + console.log("selected_file:", selected_file); + // Keeping a reference on how to reset the file input in the UI once we + // have its value, but instead of doing that we rather use a "reset" type + // input in the HTML form. + //file_input.val(null); + var file_url = $('#pub-file-url').val(); + if (selected_file) { + addPublication(biblioid, title, year, selected_file); + } else if (file_url) { + addPublicationFromUrl(biblioid, title, year, file_url); + } else { + addPublication(biblioid, title, year); + } + + }); + + $('#delete-button').click(function(evt) { + console.log("delete ..."); + var biblioid = $('#pub-biblioid-to-delete').val(); + var key = $('#key-to-delete').val(); + + if (biblioid != '') { + deletePublicationFromBib(biblioid); + } else if (key != '') { + // Better use Number.isInteger if the engine has EcmaScript 6 + if (key == '' || isNaN(key)) { + displayActionFailure("Invalid key"); + return; + } + key = Number(key); + deletePublication(key); + } + }); + + $('#clear-store-button').click(function(evt) { + clearObjectStore(); + }); + + var search_button = $('#search-list-button'); + search_button.click(function(evt) { + displayPubList(); + }); + + } + + openDb(); + addEventListeners(); + +})(); // Immediately-Invoked Function Expression (IIFE) +</pre> + +<p>{{ LiveSampleLink('Full_IndexedDB_example', "Test the online live demo") }}</p> + +<h2 id="Ver_também">Ver também</h2> + +<p>Uma leitura adicional para você encontrar mais informações.</p> + +<h3 id="Refências">Refências</h3> + +<ul> + <li><a href="/en/IndexedDB" title="https://developer.mozilla.org/en/IndexedDB">IndexedDB API Reference</a></li> + <li><a class="external" href="http://www.w3.org/TR/IndexedDB/" title="http://www.w3.org/TR/IndexedDB/">Indexed Database API Specification</a></li> + <li><a href="/en-US/docs/IndexedDB/Using_IndexedDB_in_chrome" title="/en-US/docs/IndexedDB/Using_IndexedDB_in_chrome">Using IndexedDB in chrome</a></li> + <li><a href="/en-US/docs/Web/API/IndexedDB_API/Using_JavaScript_Generators_in_Firefox">Using JavaScript generators in Firefox</a></li> + <li>IndexedDB <a class="link-https" href="https://mxr.mozilla.org/mozilla-central/find?text=&string=dom%2FindexedDB%2F.*%5C.idl&regexp=1" title="https://mxr.mozilla.org/mozilla-central/find?text=&string=dom/indexedDB/.*\.idl&regexp=1">interface files</a> in the Firefox source code</li> +</ul> + +<h3 id="Guias_e_tutoriais">Guias e tutoriais</h3> + +<ul> + <li><a href="http://www.html5rocks.com/en/tutorials/indexeddb/uidatabinding/" title="http://www.html5rocks.com/en/tutorials/indexeddb/uidatabinding/">Databinding UI Elements with IndexedDB</a></li> + <li><a class="external" href="http://msdn.microsoft.com/en-us/scriptjunkie/gg679063.aspx" title="http://msdn.microsoft.com/en-us/scriptjunkie/gg679063.aspx">IndexedDB — The Store in Your Browser</a></li> +</ul> |