Index: chrome/common/extensions/docs/templates/articles/app_codelab_webview.html |
diff --git a/chrome/common/extensions/docs/templates/articles/app_codelab_webview.html b/chrome/common/extensions/docs/templates/articles/app_codelab_webview.html |
new file mode 100644 |
index 0000000000000000000000000000000000000000..e4dcaac1445a43091bad341c3016cb347e2f2279 |
--- /dev/null |
+++ b/chrome/common/extensions/docs/templates/articles/app_codelab_webview.html |
@@ -0,0 +1,261 @@ |
+<h1 id="add-webview"> |
+ <span class="h1-step">Step 4:</span> |
+ Open External Links With a Webview |
+</h1> |
+ |
+<p class="note"> |
+ <strong>Want to start fresh from here?</strong> |
+ Find the previous step's code in the <a href="https://github.com/mangini/io13-codelab/archive/master.zip">reference code zip</a> under <strong><em>cheat_code > solution_for_step3</strong></em>. |
+</p> |
+ |
+<p>In this step, you will learn:</p> |
+ |
+<ul> |
+ <li>How to show external web content inside your app in a secure and sandboxed way.</li> |
+</ul> |
+ |
+<p> |
+ <em>Estimated time to complete this step: 10 minutes.</em> |
+ <br> |
+ To preview what you will complete in this step, <a href="#launch">jump down to the bottom of this page ↓</a>. |
+</p> |
+ |
+<h2 id="overview">Learn about the webview tag</h2> |
+ |
+<p>Some applications need to present external web content directly to the user but |
+keep them inside the application experience. For example, a news aggregator |
+might want to embed the news from external sites with all the formatting, images, |
+and behavior of the original site. For these and other usages, Chrome Apps have |
+a custom HTML tag called <a href="/apps/tags/webview">webview</a>.</p> |
+ |
+<figure> |
+ <img src="{{static}}/images/app_codelab/webview-example.png" alt="The Todo app using a webview"> |
+</figure> |
+ |
+<p class="note">A webview is a sandboxed process. For example, the enclosing Chrome App |
+(also known as the "embedder page") cannot easily access the webview's loaded DOM. |
+You can only interact with the webview using its API.</p> |
+ |
+<h2 id="implement-webview">Implement the webview tag</h2> |
+ |
+<p>Let's update our Todo app to search for URLs in the todo item text |
+in order to create a hyperlink. The link, when clicked, will open a new Chrome App window |
+(not a browser tab) with a webview presenting the content.</p> |
+ |
+<h3 id="update-permissions">Update permissions</h3> |
+ |
+<p>In <strong><em>manifest.json</em></strong>, request the <code>webview</code> permission:</p> |
+ |
+<pre data-filename="manifest.json"> |
+"permissions": ["storage", "alarms", "notifications"<b>, "webview"</b>], |
+</pre> |
+ |
+<h3 id="create-webview">Create a webview embedder page</h3> |
+ |
+<p>Create a new file in the root of your project folder and name it <strong><em>webview.html</em></strong>. |
+This file is a basic webpage with one <code><webview></code> tag:</p> |
+ |
+<pre data-filename="webview.html"> |
+<b><!DOCTYPE html> |
+<html> |
+<head> |
+ <meta charset="utf-8"> |
+</head> |
+<body> |
+ <webview style="width: 100%; height: 100%;"></webview> |
+</body> |
+</html></b> |
+</pre> |
+ |
+<h3 id="parse-urls">Parse for URLs in todo items</h3> |
+ |
+<p>At the end of <strong><em>controller.js</em></strong>, add a new method called <code>_parseForURLs()</code>:</p> |
+ |
+<pre data-filename="controller.js"> |
+ Controller.prototype._getCurrentPage = function () { |
+ return document.location.hash.split('/')[1]; |
+ }; |
+ |
+ <b>Controller.prototype._parseForURLs = function (text) {</b> |
+ <b> var re = /(https?:\/\/[^\s"<>,]+)/g;</b> |
+ <b> return text.replace(re, '<a href="$1" data-src="$1">$1</a>');</b> |
+ <b>};</b> |
+ |
+ // Export to window |
+ window.app.Controller = Controller; |
+})(window); |
+</pre> |
+ |
+<p>Whenever a string starting with "http://" or "https://" is found, a HTML anchor tag will be created to wrap around the URL.</p> |
+ |
+<h3 id="render-links">Render hyperlinks in the todo list</h3> |
+ |
+<p>Find <code>showAll()</code> in <em>controller.js</em>. Update <code>showAll()</code> |
+to parse for links by using the <code>_parseForURLs()</code> method that we added previously:</p> |
+ |
+<pre data-filename="controller.js"> |
+/** |
+ * An event to fire on load. Will get all items and display them in the |
+ * todo-list |
+ */ |
+Controller.prototype.showAll = function () { |
+ this.model.read(function (data) { |
+ <strike>this.$todoList.innerHTML = this.view.show(data);</strike> |
+ <b>this.$todoList.innerHTML = this._parseForURLs(this.view.show(data));</b> |
+ }.bind(this)); |
+}; |
+</pre> |
+ |
+<p>Do the same for <code>showActive()</code> and <code>showCompleted()</code>:</p> |
+ |
+<pre data-filename="controller.js"> |
+/** |
+ * Renders all active tasks |
+ */ |
+Controller.prototype.showActive = function () { |
+ this.model.read({ completed: 0 }, function (data) { |
+ <strike>this.$todoList.innerHTML = this.view.show(data);</strike> |
+ <b>this.$todoList.innerHTML = this._parseForURLs(this.view.show(data));</b> |
+ }.bind(this)); |
+}; |
+ |
+/** |
+ * Renders all completed tasks |
+ */ |
+Controller.prototype.showCompleted = function () { |
+ this.model.read({ completed: 1 }, function (data) { |
+ <strike>this.$todoList.innerHTML = this.view.show(data);</strike> |
+ <b>this.$todoList.innerHTML = this._parseForURLs(this.view.show(data));</b> |
+ }.bind(this)); |
+}; |
+</pre> |
+ |
+<p>And finally, add <code>_parseForURLs()</code> to <code>editItem()</code>:</p> |
+ |
+<pre data-filename="controller.js"> |
+Controller.prototype.editItem = function (id, label) { |
+ ... |
+ var onSaveHandler = function () { |
+ ... |
+ // Instead of re-rendering the whole view just update |
+ // this piece of it |
+ <strike>label.innerHTML = value;</strike> |
+ <b>label.innerHTML = this._parseForURLs(value);</b> |
+ ... |
+ }.bind(this); |
+ ... |
+} |
+</pre> |
+ |
+<p>Still in <code>editItem()</code>, fix the code so that it uses the |
+<code>innerText</code> of the label instead of the label's <code>innerHTML</code>:</p> |
+ |
+<pre data-filename="controller.js"> |
+Controller.prototype.editItem = function (id, label) { |
+ ... |
+ // Get the <strike>innerHTML</strike> <b>innerText</b> of the label instead of requesting the data from the |
+ // ORM. If this were a real DB this would save a lot of time and would avoid |
+ // a spinner gif. |
+ <strike>input.value = label.innerHTML;</strike> |
+ <b>input.value = label.innerText;</b> |
+ ... |
+} |
+</pre> |
+ |
+<h3 id="open-webview">Open new window containing webview</h3> |
+ |
+<p>Add a <code>_doShowUrl()</code> method to <em>controller.js</em>. This method will open a new Chrome App window |
+via <a href="/apps/app_window.html#method-create">chrome.app.window.create()</a> |
+with <em>webview.html</em> as the window source:</p> |
+ |
+<pre data-filename="controller.js"> |
+ Controller.prototype._parseForURLs = function (text) { |
+ var re = /(https?:\/\/[^\s"<>,]+)/g; |
+ return text.replace(re, '<a href="$1" data-src="$1">$1</a>'); |
+ }; |
+ |
+ <b>Controller.prototype._doShowUrl = function(e) {</b> |
+ <b> // only applies to elements with data-src attributes</b> |
+ <b> if (!e.target.hasAttribute('data-src')) {</b> |
+ <b> return;</b> |
+ <b> }</b> |
+ <b> e.preventDefault();</b> |
+ <b> var url = e.target.getAttribute('data-src');</b> |
+ <b> chrome.app.window.create(</b> |
+ <b> 'webview.html',</b> |
+ <b> {hidden: true}, // only show window when webview is configured</b> |
+ <b> function(appWin) {</b> |
+ <b> appWin.contentWindow.addEventListener('DOMContentLoaded',</b> |
+ <b> function(e) {</b> |
+ <b> // when window is loaded, set webview source</b> |
+ <b> var webview = appWin.contentWindow.</b> |
+ <b> document.querySelector('webview');</b> |
+ <b> webview.src = url;</b> |
+ <b> // now we can show it:</b> |
+ <b> appWin.show();</b> |
+ <b> }</b> |
+ <b> );</b> |
+ <b> });</b> |
+ <b>};</b> |
+ |
+ // Export to window |
+ window.app.Controller = Controller; |
+})(window); |
+ |
+</pre> |
+ |
+<p>In the <code>chrome.app.window.create()</code> callback, note how the webview's URL is set via the <a href="/apps/tags/webview#tag"><code>src</code> tag attribute</a>.</p> |
+ |
+<p>Lastly, add a click event listener inside the <code>Controller</code> constructor to call |
+<code>doShowUrl()</code> when a user clicks on a link:</p> |
+ |
+<pre data-filename="controller.js"> |
+function Controller(model, view) { |
+ ... |
+ this.router = new Router(); |
+ this.router.init(); |
+ |
+ <b>this.$todoList.addEventListener('click', this._doShowUrl);</b> |
+ |
+ window.addEventListener('load', function () { |
+ this._updateFilterState(); |
+ }.bind(this)); |
+ ... |
+} |
+</pre> |
+ |
+<h2 id="launch">Launch your finished Todo app</h2> |
+ |
+<p>You are done Step 4! If you reload your app and add a todo item with a full URL |
+starting with http:// or https://, you should see something like this:</p> |
+ |
+<figure> |
+ <img src="{{static}}/images/app_codelab/step4-completed.gif" alt="The Todo app with webview"/> |
+</figure> |
+ |
+<h2 id="recap">Recap APIs referenced in this step</h2> |
+ |
+<p>For more detailed information about some of the APIs introduced in this step, refer to:</p> |
+ |
+<ul> |
+ <li> |
+ <a href="/apps/declare_permissions" title="Read 'Declare Permissions' in the Chrome developer docs">Declare Permissions</a> |
+ <a href="#update-permissions" class="anchor-link-icon" title="This feature mentioned in 'Update app permissions'">↑</a> |
+ </li> |
+ <li> |
+ <a href="/apps/tags/webview" title="Read '<webview> Tag' in the Chrome developer docs"><webview> Tag</a> |
+ <a href="#overview" class="anchor-link-icon" title="This feature mentioned in 'Learn about the webview tag'">↑</a> |
+ <a href="#create-webview" class="anchor-link-icon" title="This feature mentioned in 'Create a webview embedder page'">↑</a> |
+ </li> |
+ <li> |
+ <a href="/apps/app_window.html#method-create" title="Read 'chrome.app.window.create()' in the Chrome developer docs">chrome.app.window.create()</a> |
+ <a href="#open-webview" class="anchor-link-icon" title="This feature mentioned in 'Open new window containing webview'">↑</a> |
+ </li> |
+ <li> |
+ <a href="/apps/tags/webview#tag" title="Read '<webview> Tag attributes' in the Chrome developer docs"><webview> Tag attributes</a> |
+ <a href="#open-webview" class="anchor-link-icon" title="This feature mentioned in 'Open new window containing webview'">↑</a> |
+ </li> |
+ |
+</ul> |
+ |
+<p>Ready to continue onto the next step? Go to <a href="app_codelab_images.html">Step 5 - Add images from the web »</a></p> |