diff --git a/frontend/src/Metamaps/Import.js b/frontend/src/Metamaps/Import.js index 54e256b2..d4051ddb 100644 --- a/frontend/src/Metamaps/Import.js +++ b/frontend/src/Metamaps/Import.js @@ -6,7 +6,6 @@ import _ from 'lodash' import Active from './Active' import AutoLayout from './AutoLayout' import DataModel from './DataModel' -import GlobalUI from './GlobalUI' import Map from './Map' import Synapse from './Synapse' import Topic from './Topic' @@ -389,6 +388,31 @@ const Import = { ) }, + handleText: function(text, opts = {}) { + let coords = opts.coords + if (!coords || coords.x === undefined || coords.y === undefined) { + coords = AutoLayout.getNextCoord({ mappings: DataModel.Mappings }) + } + + const name = text + const url = '' + const metacode = opts.metacode || 'Wildcard' + const importId = opts.importId || null // don't store a cidMapping + const permission = opts.permission || null // use default + const desc = opts.desc || '' + + Import.createTopicWithParameters( + name, + metacode, + permission, + desc, + url, + coords.x, + coords.y, + importId + ) + }, + /* * helper functions */ diff --git a/frontend/src/Metamaps/PasteInput.js b/frontend/src/Metamaps/PasteInput.js index 03a92f86..4083db03 100644 --- a/frontend/src/Metamaps/PasteInput.js +++ b/frontend/src/Metamaps/PasteInput.js @@ -3,12 +3,9 @@ import Import from './Import' import Util from './Util' import Visualize from './Visualize' +import URL_REGEX from '../patched/regex-weburl' const PasteInput = { - // thanks to https://github.com/kevva/url-regex - // eslint-disable-next-line no-useless-escape - URL_REGEX: new RegExp('^(?:(?:(?:[a-z]+:)?//)|www\.)(?:\S+(?::\S*)?@)?(?:localhost|(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])(?:\.(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])){3}|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,}))\.?)(?::\d{2,5})?(?:[/?#][^\s"]*)?$'), - init: function() { var self = PasteInput @@ -22,19 +19,17 @@ const PasteInput = { e = e || window.event // prevent conflict with react-dropzone file uploader - if (event.target.id !== 'infovis-canvas') return + if (e.target.id !== 'infovis-canvas') return e.preventDefault() var coords = Util.pixelsToCoords(Visualize.mGraph, { x: e.clientX, y: e.clientY }) if (e.dataTransfer.files.length > 0) { self.handleFile(e.dataTransfer.files[0], coords) } - // OMG import bookmarks 😍 + // OMG import bookmarks 😍 (Or just text :P) if (e.dataTransfer.items && e.dataTransfer.items.length > 0) { e.dataTransfer.items[0].getAsString(function(text) { - if (text.match(self.URL_REGEX)) { - self.handle(text, coords) - } + self.handle(text, coords) }) } }, false) @@ -66,15 +61,26 @@ const PasteInput = { handle: function(text, coords = {}) { var self = PasteInput - if (text.match(self.URL_REGEX)) { + if (text.match(URL_REGEX)) { Import.handleURL(text, coords) } else if (text[0] === '{') { Import.handleJSON(text) - } else if (text.match(/\t/)) { + } else if (text.match(/^[Tt]opics\t/) || text.match(/^[Ss]ynapses\t/)) { Import.handleTSV(text) } else { - // just try to see if CSV works - Import.handleCSV(text) + // Handle as plain text + let textItems = text.split('\n') + if (textItems.length === 1) { + if (textItems[0].trim() !== '') { + Import.handleText(textItems[0].trim(), coords) + } + } else if (window.confirm('Are you sure you want to create ' + textItems.length + ' new topics?')) { + textItems.forEach(item => { + if (item.trim() !== '') { + self.handle(item.trim(), coords) + } + }) + } } } } diff --git a/frontend/src/patched/regex-weburl.js b/frontend/src/patched/regex-weburl.js new file mode 100644 index 00000000..c7a5dfb7 --- /dev/null +++ b/frontend/src/patched/regex-weburl.js @@ -0,0 +1,111 @@ +/* eslint-disable */ +// START METAMAPS CODE +// From https://gist.github.com/dperini/729294. Retrieved April 11 2017. +// Minor modifications made to make it exportable by devvmh. +// END METAMAPS CODE +// +// Regular Expression for URL validation +// +// Author: Diego Perini +// Updated: 2010/12/05 +// License: MIT +// +// Copyright (c) 2010-2013 Diego Perini (http://www.iport.it) +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// +// the regular expression composed & commented +// could be easily tweaked for RFC compliance, +// it was expressly modified to fit & satisfy +// these test for an URL shortener: +// +// http://mathiasbynens.be/demo/url-regex +// +// Notes on possible differences from a standard/generic validation: +// +// - utf-8 char class take in consideration the full Unicode range +// - TLDs have been made mandatory so single names like "localhost" fails +// - protocols have been restricted to ftp, http and https only as requested +// +// Changes: +// +// - IP address dotted notation validation, range: 1.0.0.0 - 223.255.255.255 +// first and last IP address of each class is considered invalid +// (since they are broadcast/network addresses) +// +// - Added exclusion of private, reserved and/or local networks ranges +// +// - Made starting path slash optional (http://example.com?foo=bar) +// +// - Allow a dot (.) at the end of hostnames (http://example.com.) +// +// Compressed one-line versions: +// +// Javascript version +// +// /^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,}))\.?)(?::\d{2,5})?(?:[/?#]\S*)?$/i +// +// PHP version +// +// _^(?:(?:https?|ftp)://)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\x{00a1}-\x{ffff}0-9]-*)*[a-z\x{00a1}-\x{ffff}0-9]+)(?:\.(?:[a-z\x{00a1}-\x{ffff}0-9]-*)*[a-z\x{00a1}-\x{ffff}0-9]+)*(?:\.(?:[a-z\x{00a1}-\x{ffff}]{2,}))\.?)(?::\d{2,5})?(?:[/?#]\S*)?$_iuS +// +// START METAMAPS CODE +export default new RegExp( +// ORIGINAL CODE +// var re_weburl = new RegExp( +// END METAMAPS CODE + "^" + + // protocol identifier + "(?:(?:https?|ftp)://)" + + // user:pass authentication + "(?:\\S+(?::\\S*)?@)?" + + "(?:" + + // IP address exclusion + // private & local networks + "(?!(?:10|127)(?:\\.\\d{1,3}){3})" + + "(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})" + + "(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})" + + // IP address dotted notation octets + // excludes loopback network 0.0.0.0 + // excludes reserved space >= 224.0.0.0 + // excludes network & broacast addresses + // (first & last IP address of each class) + "(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])" + + "(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}" + + "(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))" + + "|" + + // host name + "(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)" + + // domain name + "(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*" + + // TLD identifier + "(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))" + + // TLD may end with dot + "\\.?" + + ")" + + // port number + "(?::\\d{2,5})?" + + // resource path + "(?:[/?#]\\S*)?" + + "$", "i" +); +/* eslint-enable */