diff options
Diffstat (limited to 'blockly/appengine/storage.js')
-rw-r--r-- | blockly/appengine/storage.js | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/blockly/appengine/storage.js b/blockly/appengine/storage.js new file mode 100644 index 0000000..8141806 --- /dev/null +++ b/blockly/appengine/storage.js @@ -0,0 +1,194 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2012 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @fileoverview Loading and saving blocks with localStorage and cloud storage. + * @author q.neutron@gmail.com (Quynh Neutron) + */ +'use strict'; + +// Create a namespace. +var BlocklyStorage = {}; + +/** + * Backup code blocks to localStorage. + * @param {!Blockly.WorkspaceSvg} workspace Workspace. + * @private + */ +BlocklyStorage.backupBlocks_ = function(workspace) { + if ('localStorage' in window) { + var xml = Blockly.Xml.workspaceToDom(workspace); + // Gets the current URL, not including the hash. + var url = window.location.href.split('#')[0]; + window.localStorage.setItem(url, Blockly.Xml.domToText(xml)); + } +}; + +/** + * Bind the localStorage backup function to the unload event. + * @param {Blockly.WorkspaceSvg=} opt_workspace Workspace. + */ +BlocklyStorage.backupOnUnload = function(opt_workspace) { + var workspace = opt_workspace || Blockly.getMainWorkspace(); + window.addEventListener('unload', + function() {BlocklyStorage.backupBlocks_(workspace);}, false); +}; + +/** + * Restore code blocks from localStorage. + * @param {Blockly.WorkspaceSvg=} opt_workspace Workspace. + */ +BlocklyStorage.restoreBlocks = function(opt_workspace) { + var url = window.location.href.split('#')[0]; + if ('localStorage' in window && window.localStorage[url]) { + var workspace = opt_workspace || Blockly.getMainWorkspace(); + var xml = Blockly.Xml.textToDom(window.localStorage[url]); + Blockly.Xml.domToWorkspace(xml, workspace); + } +}; + +/** + * Save blocks to database and return a link containing key to XML. + * @param {Blockly.WorkspaceSvg=} opt_workspace Workspace. + */ +BlocklyStorage.link = function(opt_workspace) { + var workspace = opt_workspace || Blockly.getMainWorkspace(); + var xml = Blockly.Xml.workspaceToDom(workspace); + var data = Blockly.Xml.domToText(xml); + BlocklyStorage.makeRequest_('/storage', 'xml', data, workspace); +}; + +/** + * Retrieve XML text from database using given key. + * @param {string} key Key to XML, obtained from href. + * @param {Blockly.WorkspaceSvg=} opt_workspace Workspace. + */ +BlocklyStorage.retrieveXml = function(key, opt_workspace) { + var workspace = opt_workspace || Blockly.getMainWorkspace(); + BlocklyStorage.makeRequest_('/storage', 'key', key, workspace); +}; + +/** + * Global reference to current AJAX request. + * @type {XMLHttpRequest} + * @private + */ +BlocklyStorage.httpRequest_ = null; + +/** + * Fire a new AJAX request. + * @param {string} url URL to fetch. + * @param {string} name Name of parameter. + * @param {string} content Content of parameter. + * @param {!Blockly.WorkspaceSvg} workspace Workspace. + * @private + */ +BlocklyStorage.makeRequest_ = function(url, name, content, workspace) { + if (BlocklyStorage.httpRequest_) { + // AJAX call is in-flight. + BlocklyStorage.httpRequest_.abort(); + } + BlocklyStorage.httpRequest_ = new XMLHttpRequest(); + BlocklyStorage.httpRequest_.name = name; + BlocklyStorage.httpRequest_.onreadystatechange = + BlocklyStorage.handleRequest_; + BlocklyStorage.httpRequest_.open('POST', url); + BlocklyStorage.httpRequest_.setRequestHeader('Content-Type', + 'application/x-www-form-urlencoded'); + BlocklyStorage.httpRequest_.send(name + '=' + encodeURIComponent(content)); + BlocklyStorage.httpRequest_.workspace = workspace; +}; + +/** + * Callback function for AJAX call. + * @private + */ +BlocklyStorage.handleRequest_ = function() { + if (BlocklyStorage.httpRequest_.readyState == 4) { + if (BlocklyStorage.httpRequest_.status != 200) { + BlocklyStorage.alert(BlocklyStorage.HTTPREQUEST_ERROR + '\n' + + 'httpRequest_.status: ' + BlocklyStorage.httpRequest_.status); + } else { + var data = BlocklyStorage.httpRequest_.responseText.trim(); + if (BlocklyStorage.httpRequest_.name == 'xml') { + window.location.hash = data; + BlocklyStorage.alert(BlocklyStorage.LINK_ALERT.replace('%1', + window.location.href)); + } else if (BlocklyStorage.httpRequest_.name == 'key') { + if (!data.length) { + BlocklyStorage.alert(BlocklyStorage.HASH_ERROR.replace('%1', + window.location.hash)); + } else { + BlocklyStorage.loadXml_(data, BlocklyStorage.httpRequest_.workspace); + } + } + BlocklyStorage.monitorChanges_(BlocklyStorage.httpRequest_.workspace); + } + BlocklyStorage.httpRequest_ = null; + } +}; + +/** + * Start monitoring the workspace. If a change is made that changes the XML, + * clear the key from the URL. Stop monitoring the workspace once such a + * change is detected. + * @param {!Blockly.WorkspaceSvg} workspace Workspace. + * @private + */ +BlocklyStorage.monitorChanges_ = function(workspace) { + var startXmlDom = Blockly.Xml.workspaceToDom(workspace); + var startXmlText = Blockly.Xml.domToText(startXmlDom); + function change() { + var xmlDom = Blockly.Xml.workspaceToDom(workspace); + var xmlText = Blockly.Xml.domToText(xmlDom); + if (startXmlText != xmlText) { + window.location.hash = ''; + workspace.removeChangeListener(bindData); + } + } + var bindData = workspace.addChangeListener(change); +}; + +/** + * Load blocks from XML. + * @param {string} xml Text representation of XML. + * @param {!Blockly.WorkspaceSvg} workspace Workspace. + * @private + */ +BlocklyStorage.loadXml_ = function(xml, workspace) { + try { + xml = Blockly.Xml.textToDom(xml); + } catch (e) { + BlocklyStorage.alert(BlocklyStorage.XML_ERROR + '\nXML: ' + xml); + return; + } + // Clear the workspace to avoid merge. + workspace.clear(); + Blockly.Xml.domToWorkspace(xml, workspace); +}; + +/** + * Present a text message to the user. + * Designed to be overridden if an app has custom dialogs, or a butter bar. + * @param {string} message Text to alert. + */ +BlocklyStorage.alert = function(message) { + window.alert(message); +}; |