1/** 2 * @license 3 * Copyright 2012 Google LLC 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6 7/** 8 * @fileoverview Loading and saving blocks with localStorage and cloud storage. 9 * @author [email protected] (Quynh Neutron) 10 * @author [email protected] (Jorge Marques) 11 */ 12'use strict'; 13 14/** 15 * Create the storage namespace. 16 */ 17var BlocklyStorage = {}; 18 19/** 20 * Backup code blocks to localStorage. 21 * @param {!Blockly.WorkspaceSvg} opt_workspace Workspace. 22 * @private 23 */ 24BlocklyStorage.backupBlocks_ = function(opt_workspace) { 25 if ('localStorage' in window) { 26 var workspace = opt_workspace || Blockly.getMainWorkspace(); 27 console.log('------------------------',opt_workspace); 28 var xml = Blockly.Xml.workspaceToDom(workspace); 29 var data = Blockly.Xml.domToText(xml); 30 data = UI ['workspace'].writeWorkspace (data, false); 31 localStorage.setItem(UI ['account'].currentProject.uid, data) 32 localStorage.setItem('bipes_projects', JSON.stringify(UI ['account'].projects)) 33 } 34}; 35/** 36 * Bind the localStorage backup function to the unload event. 37 * @param {Blockly.WorkspaceSvg=} opt_workspace Workspace. 38 */ 39BlocklyStorage.backupOnUnload = function(opt_workspace) { 40 var workspace = opt_workspace || Blockly.getMainWorkspace(); 41 window.addEventListener('unload', 42 function() {BlocklyStorage.backupBlocks_(workspace);}, false); 43}; 44/** 45 * Restore code blocks from localStorage. 46 * @param {Blockly.WorkspaceSvg=} opt_workspace Workspace. 47 */ 48BlocklyStorage.restoreBlocks = function(opt_workspace) { 49 if ('localStorage' in window) { 50 var workspace = opt_workspace || Blockly.getMainWorkspace(); 51 /** Import project list*/ 52 if (localStorage['bipes_projects'] && localStorage['bipes_projects'] != '[]') { 53 try { 54 let projects = JSON.parse(localStorage['bipes_projects']) 55 UI ['account'].restoreProjects (projects); 56 } catch (e) { 57 UI ['notify'].log(e) 58 } 59 } else { 60 let uid = Tool.uid (); 61 localStorage.setItem (uid, Tool.emptyXML ()) 62 let emptyProject = `{"${uid}":"${+new Date}"}`; 63 localStorage.setItem('bipes_projects', emptyProject) 64 UI ['account'].restoreProjects (JSON.parse(emptyProject)); 65 } 66 } 67}; 68 69 70 71/** 72 * Save blocks to database and return a link containing key to XML. 73 * @param {Blockly.WorkspaceSvg=} opt_workspace Workspace. 74 */ 75BlocklyStorage.link = function(opt_workspace) { 76 var workspace = opt_workspace || Blockly.getMainWorkspace(); 77 var xml = Blockly.Xml.workspaceToDom(workspace, true); 78 // Remove x/y coordinates from XML if there's only one block stack. 79 // There's no reason to store this, removing it helps with anonymity. 80 if (workspace.getTopBlocks(false).length == 1 && xml.querySelector) { 81 var block = xml.querySelector('block'); 82 if (block) { 83 block.removeAttribute('x'); 84 block.removeAttribute('y'); 85 } 86 } 87 var data = Blockly.Xml.domToText(xml); 88 data = UI ['workspace'].writeWorkspace (data, false); 89 BlocklyStorage.makeRequest_('/storage', 'xml', data, workspace); 90}; 91 92/** 93 * Retrieve XML text from database using given key. 94 * @param {string} key Key to XML, obtained from href. 95 * @param {Blockly.WorkspaceSvg=} opt_workspace Workspace. 96 */ 97BlocklyStorage.retrieveXml = function(key, opt_workspace) { 98 var workspace = opt_workspace || Blockly.getMainWorkspace(); 99 BlocklyStorage.makeRequest_('/storage', 'key', key, workspace); 100}; 101 102/** 103 * Global reference to current AJAX request. 104 * @type {XMLHttpRequest} 105 * @private 106 */ 107BlocklyStorage.httpRequest_ = null; 108 109/** 110 * Fire a new AJAX request. 111 * @param {string} url URL to fetch. 112 * @param {string} name Name of parameter. 113 * @param {string} content Content of parameter. 114 * @param {!Blockly.WorkspaceSvg} workspace Workspace. 115 * @private 116 */ 117BlocklyStorage.makeRequest_ = function(url, name, content, workspace) { 118 if (BlocklyStorage.httpRequest_) { 119 // AJAX call is in-flight. 120 BlocklyStorage.httpRequest_.abort(); 121 } 122 BlocklyStorage.httpRequest_ = new XMLHttpRequest(); 123 BlocklyStorage.httpRequest_.name = name; 124 BlocklyStorage.httpRequest_.onreadystatechange = 125 BlocklyStorage.handleRequest_; 126 BlocklyStorage.httpRequest_.open('POST', url); 127 BlocklyStorage.httpRequest_.setRequestHeader('Content-Type', 128 'application/x-www-form-urlencoded'); 129 BlocklyStorage.httpRequest_.send(name + '=' + encodeURIComponent(content)); 130 BlocklyStorage.httpRequest_.workspace = workspace; 131}; 132 133/** 134 * Callback function for AJAX call. 135 * @private 136 */ 137BlocklyStorage.handleRequest_ = function() { 138 if (BlocklyStorage.httpRequest_.readyState == 4) { 139 if (BlocklyStorage.httpRequest_.status != 200) {
140 BlocklyStorage.alert(BlocklyStorage.HTTPREQUEST_ERROR + '\n' + 141 'httpRequest_.status: ' + BlocklyStorage.httpRequest_.status); 142 } else { 143 var data = BlocklyStorage.httpRequest_.responseText.trim(); 144 if (BlocklyStorage.httpRequest_.name == 'xml') { 145 window.location.hash = data; 146 BlocklyStorage.alert(BlocklyStorage.LINK_ALERT.replace('%1', 147 window.location.href)); 148 } else if (BlocklyStorage.httpRequest_.name == 'key') { 149 if (!data.length) { 150 BlocklyStorage.alert(BlocklyStorage.HASH_ERROR.replace('%1', 151 window.location.hash)); 152 } else { 153 UI ['account'].importProject (data); 154 UI ['notify'].send ('Project imported from link!'); 155 } 156 } 157 BlocklyStorage.monitorChanges_(BlocklyStorage.httpRequest_.workspace); 158 } 159 BlocklyStorage.httpRequest_ = null; 160 } 161}; 162 163/** 164 * Start monitoring the workspace. If a change is made that changes the XML, 165 * clear the key from the URL. Stop monitoring the workspace once such a 166 * change is detected. 167 * @param {!Blockly.WorkspaceSvg} workspace Workspace. 168 * @private 169 */ 170BlocklyStorage.monitorChanges_ = function(workspace) { 171 var startXmlDom = Blockly.Xml.workspaceToDom(workspace); 172 var startXmlText = Blockly.Xml.domToText(startXmlDom); 173 function change() { 174 var xmlDom = Blockly.Xml.workspaceToDom(workspace); 175 var xmlText = Blockly.Xml.domToText(xmlDom); 176 if (startXmlText != xmlText) { 177 window.location.hash = ''; 178 workspace.removeChangeListener(change); 179 } 180 } 181 workspace.addChangeListener(change); 182}; 183 184/** 185 * Load blocks from XML. 186 * @param {string} xml Text representation of XML. 187 * @param {!Blockly.WorkspaceSvg} workspace Workspace. 188 * @private 189 */ 190BlocklyStorage.loadXml_ = function(xml, workspace) { 191 xml = UI ['workspace'].readWorkspace (xml, false); 192 try { 193 xml = Blockly.Xml.textToDom(xml); 194 } catch (e) { 195 BlocklyStorage.alert(BlocklyStorage.XML_ERROR + '\nXML: ' + xml); 196 return; 197 } 198 // Clear the workspace to avoid merge. 199 workspace.clear(); 200 Blockly.Xml.domToWorkspace(xml, workspace); 201}; 202 203/** 204 * Present a text message to the user. 205 * Designed to be overridden if an app has custom dialogs, or a butter bar. 206 * @param {string} message Text to alert. 207 */ 208BlocklyStorage.alert = function(message) { 209 window.alert(message); 210};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.