| // Copyright (c) 2016, Matt Godbolt |
| // All rights reserved. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are met: |
| // |
| // * Redistributions of source code must retain the above copyright notice, |
| // this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above copyright |
| // notice, this list of conditions and the following disclaimer in the |
| // documentation and/or other materials provided with the distribution. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
| // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| // POSSIBILITY OF SUCH DAMAGE. |
| |
| "use strict"; |
| var $ = require('jquery'); |
| var _ = require('underscore'); |
| var saveAs = require('filesaver'); |
| var Alert = require('./alert'); |
| var local = require('./local'); |
| var Promise = require('es6-promise').Promise; |
| var ga = require('./analytics'); |
| |
| function getLocalFiles() { |
| return JSON.parse(local.get('files', "{}")); |
| } |
| |
| function setLocalFile(name, file) { |
| var files = getLocalFiles(); |
| files[name] = file; |
| local.set('files', JSON.stringify(files)); |
| } |
| |
| function LoadSave() { |
| this.modal = $('#load-save'); |
| this.alertSystem = new Alert(); |
| this.alertSystem.prefixMessage = "Load-Saver: "; |
| this.onLoad = _.identity; |
| this.editorText = ''; |
| this.extension = '.txt'; |
| this.modal.find('.local-file').change(_.bind(this.onLocalFile, this)); |
| |
| this.modal.find('.save-button').click(_.bind(this.onSaveToBrowserStorage, this)); |
| this.modal.find('.save-file').click(_.bind(this.onSaveToFile, this)); |
| |
| this.fetchBuiltins(); |
| } |
| |
| LoadSave.prototype.fetchBuiltins = function () { |
| return new Promise(_.bind(function (resolve) { |
| $.getJSON('source/builtin/list', function (list) { |
| resolve(list); |
| }); |
| }, this)); |
| }; |
| |
| LoadSave.prototype.populateBuiltins = function () { |
| var isVisible = _.bind(function (entry) { |
| return this.currentLanguage && this.currentLanguage.id === entry.lang; |
| }, this); |
| return this.fetchBuiltins() |
| .then(_.bind(function (builtins) { |
| this.populate(this.modal.find('.examples'), |
| _.map(_.filter(builtins, isVisible), _.bind(function (elem) { |
| return { |
| name: elem.name, |
| load: _.bind(function () { |
| this.doLoad(elem); |
| }, this) |
| }; |
| }, this)) |
| ); |
| }, this)); |
| }; |
| |
| LoadSave.prototype.populateLocalStorage = function () { |
| this.populate( |
| this.modal.find('.local-storage'), |
| _.map(getLocalFiles(), _.bind(function (data, name) { |
| return { |
| name: name, |
| load: _.bind(function () { |
| this.onLoad(data); |
| this.modal.modal('hide'); |
| }, this) |
| }; |
| }, this))); |
| }; |
| |
| LoadSave.prototype.populate = function (root, list) { |
| root.find('li:not(.template)').remove(); |
| var template = root.find('.template'); |
| _.each(list, _.bind(function (elem) { |
| template |
| .clone() |
| .removeClass('template') |
| .appendTo(root) |
| .find('a') |
| .text(elem.name) |
| .click(elem.load); |
| }, this)); |
| }; |
| |
| LoadSave.prototype.onLocalFile = function (event) { |
| var files = event.target.files; |
| var file = files[0]; |
| var reader = new FileReader(); |
| reader.onload = _.bind(function () { |
| this.onLoad(reader.result); |
| }, this); |
| reader.readAsText(file); |
| this.modal.modal('hide'); |
| }; |
| |
| LoadSave.prototype.run = function (onLoad, editorText, currentLanguage) { |
| this.populateLocalStorage(); |
| this.onLoad = onLoad; |
| this.editorText = editorText; |
| // In case we don't send anything... |
| this.currentLanguage = currentLanguage; |
| this.extension = currentLanguage.extensions[0] || '.txt'; |
| this.modal.find('.local-file').attr('accept', _.map(currentLanguage.extensions, function (extension) { |
| return extension + ', '; |
| }, this)); |
| this.populateBuiltins().then(_.bind(function () { |
| this.modal.modal(); |
| }, this)); |
| ga.proxy('send', { |
| hitType: 'event', |
| eventCategory: 'OpenModalPane', |
| eventAction: 'LoadSave' |
| }); |
| }; |
| |
| LoadSave.prototype.onSaveToBrowserStorage = function () { |
| var name = this.modal.find('.save-name').val(); |
| if (!name) { |
| this.alertSystem.alert("Save name", "Invalid save name"); |
| return; |
| } |
| name += " (" + this.currentLanguage.name + ")"; |
| var done = _.bind(function () { |
| setLocalFile(name, this.editorText); |
| }, this); |
| if (getLocalFiles()[name] !== undefined) { |
| this.modal.modal('hide'); |
| this.alertSystem.ask( |
| "Replace current?", |
| "Do you want to replace the existing saved file '" + name + "'?", |
| {yes: done}); |
| } else { |
| done(); |
| this.modal.modal('hide'); |
| } |
| }; |
| |
| LoadSave.prototype.onSaveToFile = function () { |
| try { |
| saveAs(new Blob( |
| [this.editorText], |
| {type: "text/plain;charset=utf-8"}), |
| "Compiler Explorer Code" + this.extension); |
| } catch (e) { |
| this.alertSystem.notify('Error while saving your code. Use the clipboard instead.', { |
| group: "savelocalerror", |
| alertClass: "notification-error", |
| dismissTime: 5000 |
| }); |
| } |
| }; |
| |
| LoadSave.prototype.doLoad = function (element) { |
| // TODO: handle errors. consider promises... |
| $.getJSON('source/builtin/load/' + element.lang + '/' + element.file, |
| _.bind(function (response) { |
| this.onLoad(response.file); |
| }, this)); |
| this.modal.modal('hide'); |
| }; |
| |
| |
| module.exports = {LoadSave: LoadSave}; |