summaryrefslogtreecommitdiff
path: root/blockly/appengine/storage.js
diff options
context:
space:
mode:
Diffstat (limited to 'blockly/appengine/storage.js')
-rw-r--r--blockly/appengine/storage.js194
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);
+};