From 013e86a3b3af5680a4aa58a17dc745202116c70a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20B=C3=BCrklin?= Date: Fri, 8 May 2020 15:14:34 +0200 Subject: [PATCH 1/5] autoformatting sparql.js --- .../js/codemirror/modes/sparql/sparql.js | 486 +++++++++--------- 1 file changed, 243 insertions(+), 243 deletions(-) diff --git a/backend/static/js/codemirror/modes/sparql/sparql.js b/backend/static/js/codemirror/modes/sparql/sparql.js index 8456aec2..f99ad602 100644 --- a/backend/static/js/codemirror/modes/sparql/sparql.js +++ b/backend/static/js/codemirror/modes/sparql/sparql.js @@ -54,195 +54,195 @@ var CONTEXTS = [ ]; var COMPLEXTYPES = [ -{ - name: 'PREFIX', - definition: /PREFIX (.*)/g, - suggestions: [['PREFIX ',function(c){ return getPrefixSuggestions(c); },'\n'],['PREFIX '],['PREFIX p1: <']], - availableInContext: ['PrefixDecl','undefined'], - -}, -{ - name: 'SELECT', - definition: /SELECT (.*)/g, - suggestions: [['SELECT WHERE {\n \n}\n']], - availableInContext: ['PrefixDecl','undefined','SubQuery'], - onlyOnce: true, - -}, -{ - name: 'DISTINCT', - definition: /DISTINCT|[?\w]+ [?\w]*/g, - suggestions: [['DISTINCT ']], - availableInContext: ['SelectClause'], - onlyOnce: true, - onlyOncePerVariation: false, -}, -{ - name: 'VARIABLE', - definition: /\?([a-zA-Z]*)/g, - suggestions: [[function(c){ var a = []; $(getVariables(c,true)).each(function(k,v){ a.push(v+' ')}); return a;}]], - availableInContext: ['SelectClause','OrderCondition','GroupCondition'], - -}, -{ - name: 'TEXT', - definition: /TEXT\((.*)\)/g, - suggestions: [['TEXT(',function(c){ var a = []; $(getVariables(c,true,"text")).each(function(k,v){ a.push(v)}); return a; },') ']], - availableInContext: ['SelectClause'], - -}, -{ - name: 'SCORE', - definition: /SCORE\((.*)\)/g, - suggestions: [['SCORE(',function(c){ var a = []; $(getVariables(c,true,"text")).each(function(k,v){ a.push(v)}); return a; },') ']], - availableInContext: ['SelectClause','OrderCondition'], - -}, -{ - name: 'MIN', - definition: /\(MIN\((.*)\) as (.*)\)/g, - suggestions: [['(MIN(',function(c){ if(getContextByName('SolutionModifier') && getContextByName('SolutionModifier')['content'].indexOf('GROUP BY') != -1){ return getVariables(c,true); } else { return false; } },') as ?min_{[0]}) ']], - availableInContext: ['SelectClause','OrderCondition'], - -}, -{ - name: 'MAX', - definition: /\(MAX\((.*)\) as (.*)\)/g, - suggestions: [['(MAX(',function(c){ if(getContextByName('SolutionModifier') && getContextByName('SolutionModifier')['content'].indexOf('GROUP BY') != -1){ return getVariables(c,true); } else { return false; } },') as ?max_{[0]}) ']], - availableInContext: ['SelectClause','OrderCondition'], - -}, -{ - name: 'SUM', - definition: /\(SUM\((.*)\) as (.*)\)/g, - suggestions: [['(SUM(',['DISTINCT ',''],function(c){ if(getContextByName('SolutionModifier') && getContextByName('SolutionModifier')['content'].indexOf('GROUP BY') != -1){ return getVariables(c,true); } else { return false; } },') as ?sum_{[1]}) ']], - availableInContext: ['SelectClause','OrderCondition'], - -}, -{ - name: 'AVG', - definition: /\(AVG\((.*)\) as (.*)\)/g, - suggestions: [['(AVG(',['DISTINCT ',''],function(c){ if(getContextByName('SolutionModifier') && getContextByName('SolutionModifier')['content'].indexOf('GROUP BY') != -1){ return getVariables(c,true); } else { return false; } },') as ?avg_{[1]}) ']], - availableInContext: ['SelectClause','OrderCondition'], - -}, -{ - name: 'SAMPLE', - definition: /\(SAMPLE\((.*)\) as (.*)\)/g, - suggestions: [['(SAMPLE(',function(c){ if(getContextByName('SolutionModifier') && getContextByName('SolutionModifier')['content'].indexOf('GROUP BY') != -1){ return getVariables(c,true); } else { return false; } },') as ?sample_{[0]}) ']], - availableInContext: ['SelectClause'], - -}, -{ - name: 'COUNT', - definition: /\(COUNT\((.*)\) as (.*)\)/g, - suggestions: [['(COUNT(',['DISTINCT ',''],function(c){ if(getContextByName('SolutionModifier') && getContextByName('SolutionModifier')['content'].indexOf('GROUP BY') != -1){ return getVariables(c,true); } else { return false; } },') as ?count_{[1]}) ']], - availableInContext: ['SelectClause'], - -}, -{ - name: 'GROUP_CONCAT', - definition: /\(GROUP_CONCAT\((.*)\) as (.*)\)/g, - suggestions: [['(GROUP_CONCAT(',['DISTINCT ',''],function(c){ if(getContextByName('SolutionModifier') && getContextByName('SolutionModifier')['content'].indexOf('GROUP BY') != -1){ return getVariables(c,true); } else { return false; } },') as ?concat_{[1]}) ']], - availableInContext: ['SelectClause'], - -}, -{ - name: 'LIMIT', - definition: /\bLIMIT ([0-9+])/g, - suggestions: [['LIMIT ',[1,10,100,1000],'\n']], - availableInContext: ['SolutionModifier'], - onlyOnce: true, - -}, -{ - name: 'TEXTLIMIT', - definition: /TEXTLIMIT ([0-9+])/g, - suggestions: [['TEXTLIMIT ',[2,5,10],'\n']], - availableInContext: ['SolutionModifier'], - onlyOnce: true, - -}, -{ - name: 'ASC', - definition: /ASC(\?.*)/g, - suggestions: [['ASC(',function(c){ var a = getVariables(c); for (var v of getVariables(c,undefined,"text")) { a.push("SCORE("+v+")"); }; return a; },') ']], - availableInContext: ['OrderCondition'], - -}, -{ - name: 'DESC', - definition: /DESC(\?.*)/g, - suggestions: [['DESC(',function(c){ var a = getVariables(c); for (var v of getVariables(c,undefined,"text")) { a.push("SCORE("+v+")"); }; return a; },') ']], - availableInContext: ['OrderCondition'], - -}, -{ - name: 'ORDER BY', - definition: /ORDER BY .*/g, - suggestions: [['ORDER BY ']], - availableInContext: ['SolutionModifier'], - onlyOnce: true, - -}, -{ - name: 'GROUP BY', - definition: /GROUP BY \?(.+)/g, - suggestions: [['GROUP BY ']], - availableInContext: ['SolutionModifier'], - onlyOnce: true, - -}, -{ - name: 'HAVING', - definition: /HAVING \?(.+)/g, - suggestions: [['HAVING (', function(c){ return getVariables(c);},' ']], - availableInContext: ['SolutionModifier'], - onlyOnce: true, - -}, -{ - name: 'TRIPLE', - suggestions: [[ function(c){ return getDynamicSuggestions(c); }]], - availableInContext: ['WhereClause','OptionalClause','UnionClause'], - onlyOncePerVariation: false, -}, -{ - name: 'FILTER', - definition: /FILTER \((.*)/g, - suggestions: [['FILTER (', function(c){ return getVariables(c,undefined,undefined,FILTER_TYPES);},' ']], - availableInContext: ['WhereClause','OptionalClause','UnionClause'], - requiresEmptyLine: true, - onlyOncePerVariation: false -}, -{ - name: 'FILTER LANGUAGE', - definition: /FILTER langMatches(.*)/g, - suggestions: [['FILTER langMatches(lang(', function(c){ var a = []; for (var v of getVariables(c,undefined,undefined,LANGUAGELITERAL)) { if(editor.getValue().indexOf("FILTER langMatches(lang("+v) == -1){ a.push(v); } }; return a; }, '), ', LANGUAGESĀ ,') .\n']], - availableInContext: ['WhereClause','OptionalClause','UnionClause'], - requiresEmptyLine: true, -}, -{ - name: 'SUBQUERY', - suggestions: [['{\n\n}']], - availableInContext: ['WhereClause', 'OptionalClause', 'SubQuery'], - suggestOnlyWhenMatch: true, - requiresEmptyLine: true, -}, -{ - name: 'OPTIONAL', - suggestions: [['OPTIONAL {\n\n}\n']], - availableInContext: ['WhereClause'], - suggestOnlyWhenMatch: true, - requiresEmptyLine: true, -}, -{ - name: 'UNION', - suggestions: [['UNION {\n\n}\n']], - availableInContext: ['WhereClause'], - suggestOnlyWhenMatch: true, - requiresEmptyLine: true, -}, + { + name: 'PREFIX', + definition: /PREFIX (.*)/g, + suggestions: [['PREFIX ', function (c) { return getPrefixSuggestions(c); }, '\n'], ['PREFIX '], ['PREFIX p1: <']], + availableInContext: ['PrefixDecl', 'undefined'], + + }, + { + name: 'SELECT', + definition: /SELECT (.*)/g, + suggestions: [['SELECT WHERE {\n \n}\n']], + availableInContext: ['PrefixDecl', 'undefined', 'SubQuery'], + onlyOnce: true, + + }, + { + name: 'DISTINCT', + definition: /DISTINCT|[?\w]+ [?\w]*/g, + suggestions: [['DISTINCT ']], + availableInContext: ['SelectClause'], + onlyOnce: true, + onlyOncePerVariation: false, + }, + { + name: 'VARIABLE', + definition: /\?([a-zA-Z]*)/g, + suggestions: [[function (c) { var a = []; $(getVariables(c, true)).each(function (k, v) { a.push(v + ' ') }); return a; }]], + availableInContext: ['SelectClause', 'OrderCondition', 'GroupCondition'], + + }, + { + name: 'TEXT', + definition: /TEXT\((.*)\)/g, + suggestions: [['TEXT(', function (c) { var a = []; $(getVariables(c, true, "text")).each(function (k, v) { a.push(v) }); return a; }, ') ']], + availableInContext: ['SelectClause'], + + }, + { + name: 'SCORE', + definition: /SCORE\((.*)\)/g, + suggestions: [['SCORE(', function (c) { var a = []; $(getVariables(c, true, "text")).each(function (k, v) { a.push(v) }); return a; }, ') ']], + availableInContext: ['SelectClause', 'OrderCondition'], + + }, + { + name: 'MIN', + definition: /\(MIN\((.*)\) as (.*)\)/g, + suggestions: [['(MIN(', function (c) { if (getContextByName('SolutionModifier') && getContextByName('SolutionModifier')['content'].indexOf('GROUP BY') != -1) { return getVariables(c, true); } else { return false; } }, ') as ?min_{[0]}) ']], + availableInContext: ['SelectClause', 'OrderCondition'], + + }, + { + name: 'MAX', + definition: /\(MAX\((.*)\) as (.*)\)/g, + suggestions: [['(MAX(', function (c) { if (getContextByName('SolutionModifier') && getContextByName('SolutionModifier')['content'].indexOf('GROUP BY') != -1) { return getVariables(c, true); } else { return false; } }, ') as ?max_{[0]}) ']], + availableInContext: ['SelectClause', 'OrderCondition'], + + }, + { + name: 'SUM', + definition: /\(SUM\((.*)\) as (.*)\)/g, + suggestions: [['(SUM(', ['DISTINCT ', ''], function (c) { if (getContextByName('SolutionModifier') && getContextByName('SolutionModifier')['content'].indexOf('GROUP BY') != -1) { return getVariables(c, true); } else { return false; } }, ') as ?sum_{[1]}) ']], + availableInContext: ['SelectClause', 'OrderCondition'], + + }, + { + name: 'AVG', + definition: /\(AVG\((.*)\) as (.*)\)/g, + suggestions: [['(AVG(', ['DISTINCT ', ''], function (c) { if (getContextByName('SolutionModifier') && getContextByName('SolutionModifier')['content'].indexOf('GROUP BY') != -1) { return getVariables(c, true); } else { return false; } }, ') as ?avg_{[1]}) ']], + availableInContext: ['SelectClause', 'OrderCondition'], + + }, + { + name: 'SAMPLE', + definition: /\(SAMPLE\((.*)\) as (.*)\)/g, + suggestions: [['(SAMPLE(', function (c) { if (getContextByName('SolutionModifier') && getContextByName('SolutionModifier')['content'].indexOf('GROUP BY') != -1) { return getVariables(c, true); } else { return false; } }, ') as ?sample_{[0]}) ']], + availableInContext: ['SelectClause'], + + }, + { + name: 'COUNT', + definition: /\(COUNT\((.*)\) as (.*)\)/g, + suggestions: [['(COUNT(', ['DISTINCT ', ''], function (c) { if (getContextByName('SolutionModifier') && getContextByName('SolutionModifier')['content'].indexOf('GROUP BY') != -1) { return getVariables(c, true); } else { return false; } }, ') as ?count_{[1]}) ']], + availableInContext: ['SelectClause'], + + }, + { + name: 'GROUP_CONCAT', + definition: /\(GROUP_CONCAT\((.*)\) as (.*)\)/g, + suggestions: [['(GROUP_CONCAT(', ['DISTINCT ', ''], function (c) { if (getContextByName('SolutionModifier') && getContextByName('SolutionModifier')['content'].indexOf('GROUP BY') != -1) { return getVariables(c, true); } else { return false; } }, ') as ?concat_{[1]}) ']], + availableInContext: ['SelectClause'], + + }, + { + name: 'LIMIT', + definition: /\bLIMIT ([0-9+])/g, + suggestions: [['LIMIT ', [1, 10, 100, 1000], '\n']], + availableInContext: ['SolutionModifier'], + onlyOnce: true, + + }, + { + name: 'TEXTLIMIT', + definition: /TEXTLIMIT ([0-9+])/g, + suggestions: [['TEXTLIMIT ', [2, 5, 10], '\n']], + availableInContext: ['SolutionModifier'], + onlyOnce: true, + + }, + { + name: 'ASC', + definition: /ASC(\?.*)/g, + suggestions: [['ASC(', function (c) { var a = getVariables(c); for (var v of getVariables(c, undefined, "text")) { a.push("SCORE(" + v + ")"); }; return a; }, ') ']], + availableInContext: ['OrderCondition'], + + }, + { + name: 'DESC', + definition: /DESC(\?.*)/g, + suggestions: [['DESC(', function (c) { var a = getVariables(c); for (var v of getVariables(c, undefined, "text")) { a.push("SCORE(" + v + ")"); }; return a; }, ') ']], + availableInContext: ['OrderCondition'], + + }, + { + name: 'ORDER BY', + definition: /ORDER BY .*/g, + suggestions: [['ORDER BY ']], + availableInContext: ['SolutionModifier'], + onlyOnce: true, + + }, + { + name: 'GROUP BY', + definition: /GROUP BY \?(.+)/g, + suggestions: [['GROUP BY ']], + availableInContext: ['SolutionModifier'], + onlyOnce: true, + + }, + { + name: 'HAVING', + definition: /HAVING \?(.+)/g, + suggestions: [['HAVING (', function (c) { return getVariables(c); }, ' ']], + availableInContext: ['SolutionModifier'], + onlyOnce: true, + + }, + { + name: 'TRIPLE', + suggestions: [[function (c) { return getDynamicSuggestions(c); }]], + availableInContext: ['WhereClause', 'OptionalClause', 'UnionClause'], + onlyOncePerVariation: false, + }, + { + name: 'FILTER', + definition: /FILTER \((.*)/g, + suggestions: [['FILTER (', function (c) { return getVariables(c, undefined, undefined, FILTER_TYPES); }, ' ']], + availableInContext: ['WhereClause', 'OptionalClause', 'UnionClause'], + requiresEmptyLine: true, + onlyOncePerVariation: false + }, + { + name: 'FILTER LANGUAGE', + definition: /FILTER langMatches(.*)/g, + suggestions: [['FILTER langMatches(lang(', function (c) { var a = []; for (var v of getVariables(c, undefined, undefined, LANGUAGELITERAL)) { if (editor.getValue().indexOf("FILTER langMatches(lang(" + v) == -1) { a.push(v); } }; return a; }, '), ', LANGUAGES, ') .\n']], + availableInContext: ['WhereClause', 'OptionalClause', 'UnionClause'], + requiresEmptyLine: true, + }, + { + name: 'SUBQUERY', + suggestions: [['{\n\n}']], + availableInContext: ['WhereClause', 'OptionalClause', 'SubQuery'], + suggestOnlyWhenMatch: true, + requiresEmptyLine: true, + }, + { + name: 'OPTIONAL', + suggestions: [['OPTIONAL {\n\n}\n']], + availableInContext: ['WhereClause'], + suggestOnlyWhenMatch: true, + requiresEmptyLine: true, + }, + { + name: 'UNION', + suggestions: [['UNION {\n\n}\n']], + availableInContext: ['WhereClause'], + suggestOnlyWhenMatch: true, + requiresEmptyLine: true, + }, ]; @@ -259,46 +259,46 @@ var COMPLEXTYPES = [ // CodeMirror, copyright (c) by Marijn Haverbeke and others // Distributed under an MIT license: http://codemirror.net/LICENSE -(function(mod) { +(function (mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); else if (typeof define == "function" && define.amd) // AMD define(["../../lib/codemirror"], mod); else // Plain browser env mod(CodeMirror); -})(function(CodeMirror) { +})(function (CodeMirror) { "use strict"; - CodeMirror.defineMode("sparql", function(config) { + CodeMirror.defineMode("sparql", function (config) { var indentUnit = config.indentUnit; var curPunc; - // ----------------------------------------------------- - // List and detect language keywords - // ----------------------------------------------------- + // ----------------------------------------------------- + // List and detect language keywords + // ----------------------------------------------------- - function wordRegexp(words) { + function wordRegexp(words) { return new RegExp("^(?:" + words.join("|") + ")$", "i"); } var keywords = wordRegexp(KEYWORDS); var functions = wordRegexp(FUNCTIONS); - // ----------------------------------------------------- - // Detect tokens and their types - // ----------------------------------------------------- + // ----------------------------------------------------- + // Detect tokens and their types + // ----------------------------------------------------- function tokenBase(stream, state) { var ch = stream.next(); var before = ""; - + curPunc = null; - + if (ch == "?") { - before = getBefore(stream, /\s/); - var isAggregate = (before != "" && stream.peekback(before.length+3).match(/\s/) && stream.peekback(before.length+2) == "a" && stream.peekback(before.length+1) == "s"); + before = getBefore(stream, /\s/); + var isAggregate = (before != "" && stream.peekback(before.length + 3).match(/\s/) && stream.peekback(before.length + 2) == "a" && stream.peekback(before.length + 1) == "s"); stream.match(/^[\w\d]*/); if (isAggregate) { - return "variable aggregate-variable"; + return "variable aggregate-variable"; } return "variable"; } else if (ch == "\"" || ch == "'") { @@ -311,28 +311,28 @@ var COMPLEXTYPES = [ curPunc = ch; return "control"; } else if (ch == "<") { - before = getBefore(stream, /[\s:]/); + before = getBefore(stream, /[\s:]/); stream.match(/^[\S]*>/); - + if (before.indexOf(":") != -1) { - return "prefix-declaration prefix-value"; + return "prefix-declaration prefix-value"; } return "entity"; - } else if (ch == "@") { + } else if (ch == "@") { stream.match(/[\w-]*@/); return "string string-language"; - } else if (ch == "#") { + } else if (ch == "#") { stream.match(/.*/); return "comment"; - } else { - before = getBefore(stream, /:/); + } else { + before = getBefore(stream, /:/); var match = stream.match(/[_\w\d\.-]*(:(\s*))?/); var word = stream.current(); if (match && match[2] !== undefined) { - if (match[2].length > 0) { - stream.backUp(match[2].length); - return "prefix-declaration prefix-name"; - } + if (match[2].length > 0) { + stream.backUp(match[2].length); + return "prefix-declaration prefix-name"; + } return "entity prefixed-entity prefix-name"; } else if (word.match(/^[.|<|>|=]+$/)) { return "control"; @@ -341,44 +341,44 @@ var COMPLEXTYPES = [ } else if (functions.test(word)) { return "function"; } else if (before.length > 0) { - return "entity prefixed-entity entity-name" - } else if (word.match(/[\d]+/)) { - return "literal"; - } - // console.warn("Could not tokenize word: " + word); + return "entity prefixed-entity entity-name" + } else if (word.match(/[\d]+/)) { + return "literal"; + } + // console.warn("Could not tokenize word: " + word); return "other"; } } - - function getBefore(stream, chars) { - var before = ""; - var i = 1; - var ch = stream.peekback(i); - while (ch != null && ch.match(chars)) { - before = ch + before; - ch = stream.peekback(++i); - } - return before; - } - - // support escaping inside strings + + function getBefore(stream, chars) { + var before = ""; + var i = 1; + var ch = stream.peekback(i); + while (ch != null && ch.match(chars)) { + before = ch + before; + ch = stream.peekback(++i); + } + return before; + } + + // support escaping inside strings function tokenLiteral(quote) { - return function(stream, state) { + return function (stream, state) { var escaped = false; var ch; while ((ch = stream.next()) != null) { - if (ch == quote && !escaped) { - state.tokenize = tokenBase; - break; - } + if (ch == quote && !escaped) { + state.tokenize = tokenBase; + break; + } escaped = !escaped && ch == "\\"; } return "string string-value"; }; } - // Go deeper into scope + // Go deeper into scope function pushContext(state, type, col) { state.context = { prev: state.context, @@ -388,7 +388,7 @@ var COMPLEXTYPES = [ }; } - // Escape from scope + // Escape from scope function popContext(state) { state.indent = state.context.indent; state.context = state.context.prev; @@ -396,7 +396,7 @@ var COMPLEXTYPES = [ return { - startState: function() { + startState: function () { return { tokenize: tokenBase, context: null, @@ -405,7 +405,7 @@ var COMPLEXTYPES = [ }; }, - token: function(stream, state) { + token: function (stream, state) { if (stream.sol()) { if (state.context && state.context.align == null) state.context.align = false; state.indent = stream.indentation(); @@ -440,7 +440,7 @@ var COMPLEXTYPES = [ return style; }, - indent: function(state, textAfter) { + indent: function (state, textAfter) { var firstChar = textAfter && textAfter.charAt(0); var context = state.context; if (/[\]\}]/.test(firstChar)) From 2c71464889a3b6bf1afa15135353a9c62ef89251 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20B=C3=BCrklin?= Date: Fri, 8 May 2020 15:16:37 +0200 Subject: [PATCH 2/5] suggest lang instead of langMatches. Fixes #20 --- backend/static/js/codemirror/modes/sparql/sparql.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/static/js/codemirror/modes/sparql/sparql.js b/backend/static/js/codemirror/modes/sparql/sparql.js index f99ad602..c167740c 100644 --- a/backend/static/js/codemirror/modes/sparql/sparql.js +++ b/backend/static/js/codemirror/modes/sparql/sparql.js @@ -217,8 +217,8 @@ var COMPLEXTYPES = [ }, { name: 'FILTER LANGUAGE', - definition: /FILTER langMatches(.*)/g, - suggestions: [['FILTER langMatches(lang(', function (c) { var a = []; for (var v of getVariables(c, undefined, undefined, LANGUAGELITERAL)) { if (editor.getValue().indexOf("FILTER langMatches(lang(" + v) == -1) { a.push(v); } }; return a; }, '), ', LANGUAGES, ') .\n']], + definition: /FILTER (lang(.*))/g, + suggestions: [['FILTER (lang(', function (c) { var a = []; for (var v of getVariables(c, undefined, undefined, LANGUAGELITERAL)) { if (editor.getValue().indexOf("FILTER langMatches(lang(" + v) == -1) { a.push(v); } }; return a; }, ') = ', LANGUAGES, ') .\n']], availableInContext: ['WhereClause', 'OptionalClause', 'UnionClause'], requiresEmptyLine: true, }, From 9c92f000bda0059ea6bb9eec68974f382e32a0ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20B=C3=BCrklin?= Date: Fri, 8 May 2020 15:52:44 +0200 Subject: [PATCH 3/5] Escape %CURRENT_WORD% for use in regex filter --- backend/static/js/codemirror/modes/sparql/sparql-hint.js | 1 + backend/static/js/helper.js | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/backend/static/js/codemirror/modes/sparql/sparql-hint.js b/backend/static/js/codemirror/modes/sparql/sparql-hint.js index a88619d4..b2ea7d03 100755 --- a/backend/static/js/codemirror/modes/sparql/sparql-hint.js +++ b/backend/static/js/codemirror/modes/sparql/sparql-hint.js @@ -530,6 +530,7 @@ function getDynamicSuggestions(context) { } function replaceQueryPlaceholders(completionQuery, word, prefixes, lines, words) { + word = escapeRegExp(word); var word_with_bracket = ((word.startsWith("<") || word.startsWith('"')) ? "" : "<") + word.replace(/'/g, "\\'"); sparqlLines = completionQuery.replace(/%").text(str).html(); } +function escapeRegExp(string) { + // Escapes strings for use in QLever REGEX filter + return string.replace(/[.*+\-?^${}()|[\]\\]/g, '\\\\$&'); // $& means the whole matched string +} + function getShortStr(str, maxLength, column = undefined) { str = str.replace(/_/g, ' '); var pos; From cc8004853f569623f67813376afb87960dd34301 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20B=C3=BCrklin?= Date: Fri, 22 May 2020 11:27:56 +0200 Subject: [PATCH 4/5] Added option to not show subject suggestions in empty lines --- backend/admin.py | 2 +- ...0056_backend_suggestsubjectsinemptyline.py | 19 +++++++++++++++++++ backend/models.py | 5 +++++ .../js/codemirror/modes/sparql/sparql-hint.js | 3 ++- backend/templates/index.html | 1 + 5 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 backend/migrations/0056_backend_suggestsubjectsinemptyline.py diff --git a/backend/admin.py b/backend/admin.py index a4052d1c..bdf1f207 100644 --- a/backend/admin.py +++ b/backend/admin.py @@ -27,7 +27,7 @@ class BackendAdmin(ImportExportModelAdmin): 'fields': ('ntFilePath',), }), ('UI Suggestions', { - 'fields': ('maxDefault', 'fillPrefixes', 'filterEntities', 'filteredLanguage', 'supportedKeywords', 'supportedFunctions', 'suggestPrefixnamesForPredicates', 'supportedPredicateSuggestions'), + 'fields': ('maxDefault', 'fillPrefixes', 'filterEntities', 'filteredLanguage', 'supportedKeywords', 'supportedFunctions', 'suggestPrefixnamesForPredicates', 'suggestSubjectsInEmptyLine', 'supportedPredicateSuggestions'), }), ('Backend Suggestions', { 'fields': ('suggestSubjects', 'suggestPredicates', 'suggestObjects', 'dynamicSuggestions', 'replacePredicates'), diff --git a/backend/migrations/0056_backend_suggestsubjectsinemptyline.py b/backend/migrations/0056_backend_suggestsubjectsinemptyline.py new file mode 100644 index 00000000..8b0548e0 --- /dev/null +++ b/backend/migrations/0056_backend_suggestsubjectsinemptyline.py @@ -0,0 +1,19 @@ +# Generated by Django 3.0.2 on 2020-05-22 09:23 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('backend', '0055_merge_20200425_1057'), + ] + + operations = [ + migrations.AddField( + model_name='backend', + name='suggestSubjectsInEmptyLine', + field=models.BooleanField( + default=False, help_text='Suggest subjects when no character has been typed yet.', verbose_name='Suggest subject in empty lines.'), + ), + ] diff --git a/backend/models.py b/backend/models.py index 75a9770d..a1faeeb4 100644 --- a/backend/models.py +++ b/backend/models.py @@ -142,6 +142,11 @@ class Backend(models.Model): help_text="Suggest Prefix names without a particular entity when autocompleting predicates.", verbose_name="Suggest prefix names for predicates.") + suggestSubjectsInEmptyLine = models.BooleanField( + default=False, + help_text="Suggest subjects when no character has been typed yet.", + verbose_name="Suggest subjects in empty lines.") + fillPrefixes = models.BooleanField( default=True, help_text="Replace prefixes in suggestions even if they are not yet declared in the query. Add prefix declarations if a suggestion with not yet declared prefix is picked.", diff --git a/backend/static/js/codemirror/modes/sparql/sparql-hint.js b/backend/static/js/codemirror/modes/sparql/sparql-hint.js index b2ea7d03..ba4a9d17 100755 --- a/backend/static/js/codemirror/modes/sparql/sparql-hint.js +++ b/backend/static/js/codemirror/modes/sparql/sparql-hint.js @@ -417,12 +417,13 @@ function getDynamicSuggestions(context) { if (words.length == 1) { suggestVariables = "both"; appendToSuggestions = " "; - if (SUGGESTSUBJECTS.length > 0) { + if (SUGGESTSUBJECTS.length > 0 && (word.length > 0 || SUGGEST_SUBJECTS_IN_EMPTY_LINE)) { completionQuery = SUGGESTSUBJECTS; nameList = subjectNames; } else { sendSparql = false; } + } else if (words.length == 2) { suggestVariables = word.startsWith('?') ? "normal" : false; appendToSuggestions = " "; diff --git a/backend/templates/index.html b/backend/templates/index.html index 9dbb5dac..c0acf9d2 100644 --- a/backend/templates/index.html +++ b/backend/templates/index.html @@ -41,6 +41,7 @@ var FILLPREFIXES = {{ backend.fillPrefixes|lower }}; var FILTER_TYPES = {% if backend.filterEntities %}ENTITY{% else %}LITERAL{% endif %}; var REPLACE_PREDICATES = {% autoescape off %}{{ backend.replacePredicatesList }}{% endautoescape %}; + var SUGGEST_SUBJECTS_IN_EMPTY_LINE = {{ backend.suggestSubjectsInEmptyLine|lower }}; var examples = []; {% for example in examples %} examples.push(`{{ example.query|safe }}`); From b18c13b451cc426aea4c7a6d3df74de85ac91ab5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20B=C3=BCrklin?= Date: Fri, 22 May 2020 11:44:57 +0200 Subject: [PATCH 5/5] removed unneeded fields from backend --- backend/admin.py | 2 +- backend/migrations/0057_auto_20200522_1134.py | 30 +++++++++++++++++++ backend/models.py | 22 ++------------ backend/templates/index.html | 3 -- resources/backend-sample.csv | 11 +++---- 5 files changed, 37 insertions(+), 31 deletions(-) create mode 100644 backend/migrations/0057_auto_20200522_1134.py diff --git a/backend/admin.py b/backend/admin.py index bdf1f207..b77c6c65 100644 --- a/backend/admin.py +++ b/backend/admin.py @@ -33,7 +33,7 @@ class BackendAdmin(ImportExportModelAdmin): 'fields': ('suggestSubjects', 'suggestPredicates', 'suggestObjects', 'dynamicSuggestions', 'replacePredicates'), }), ('Showing names', { - 'fields': ('subjectName', 'alternativeSubjectName', 'predicateName', 'alternativePredicateName', 'objectName', 'alternativeObjectName'), + 'fields': ('subjectName', 'predicateName', 'objectName'), }), ) diff --git a/backend/migrations/0057_auto_20200522_1134.py b/backend/migrations/0057_auto_20200522_1134.py new file mode 100644 index 00000000..557b59ac --- /dev/null +++ b/backend/migrations/0057_auto_20200522_1134.py @@ -0,0 +1,30 @@ +# Generated by Django 3.0.2 on 2020-05-22 09:34 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('backend', '0056_backend_suggestsubjectsinemptyline'), + ] + + operations = [ + migrations.RemoveField( + model_name='backend', + name='alternativeObjectName', + ), + migrations.RemoveField( + model_name='backend', + name='alternativePredicateName', + ), + migrations.RemoveField( + model_name='backend', + name='alternativeSubjectName', + ), + migrations.AlterField( + model_name='backend', + name='suggestSubjectsInEmptyLine', + field=models.BooleanField(default=False, help_text='Suggest subjects when no character has been typed yet.', verbose_name='Suggest subjects in empty lines.'), + ), + ] diff --git a/backend/models.py b/backend/models.py index a1faeeb4..4f7f3db6 100644 --- a/backend/models.py +++ b/backend/models.py @@ -75,36 +75,18 @@ class Backend(models.Model): help_text="Need help?
Clause that tells QLever UI the name of a subject (without prefixes). Qlever UI expects the following variables to be used:
  -  ?qleverui_entity: The subject that we want to get the name of
  -  ?qleverui_name: The variable that will hold the subject's name
Your clause should end in a dot '.' or closing bracket '}'
Your clause will be used as following:
SELECT ?qleverui_name WHERE {
    ?qleverui_entity <predicate> <object>
    OPTIONAL {
        subject name clause
    }
}
", verbose_name="Subject name clause") - alternativeSubjectName = models.TextField( - default='', - blank=True, - help_text="Need help?
Clause that tells QLever UI the alternative name of a subject (without prefixes). Qlever UI expects the following variables to be used:
  -  ?qleverui_entity: The subject that we want to get the name of
  -  ?qleverui_altname: The variable that will hold the subject's alternative name
Your clause should end in a dot '.' or closing bracket '}'
Your clause will be used as following:
SELECT ?qleverui_altname WHERE {
    ?qleverui_entity <predicate> <object>
    OPTIONAL {
        alternative subject name clause
    }
}
", - verbose_name="Alternative subject name clause") - predicateName = models.TextField( default='', blank=True, help_text="Need help?
Clause that tells QLever UI the name of a predicate (without prefixes). Qlever UI expects the following variables to be used:
  -  ?qleverui_entity: The predicate that we want to get the name of
  -  ?qleverui_name: The variable that will hold the predicate's name
Your clause should end in a dot '.' or closing bracket '}'
Your clause will be used as following:
SELECT ?qleverui_name WHERE {
    <subject> ?qleverui_entity <object>
    OPTIONAL {
        predicate name clause
    }
}
", verbose_name="Predicate name clause") - alternativePredicateName = models.TextField( - default='', - blank=True, - help_text="Need help?
Clause that tells QLever UI the alternative name of a predicate (without prefixes). Qlever UI expects the following variables to be used:
  -  ?qleverui_entity: The predicate that we want to get the name of
  -  ?qleverui_altname: The variable that will hold the predicate's alternative name
Your clause should end in a dot '.' or closing bracket '}'
Your clause will be used as following:
SELECT ?qleverui_altname WHERE {
    <subject> ?qleverui_entity <object>
    OPTIONAL {
        alternative predicate name clause
    }
}
", - verbose_name="Alternative predicate name clause") - objectName = models.TextField( default='', blank=True, help_text="Need help?
Clause that tells QLever UI the name of an object (without prefixes). Qlever UI expects the following variables to be used:
  -  ?qleverui_entity: The object that we want to get the name of
  -  ?qleverui_name: The variable that will hold the object's name
Your clause should end in a dot '.' or closing bracket '}'
Your clause will be used as following:
SELECT ?qleverui_name WHERE {
    <subject> <predicate> ?qleverui_entity
    OPTIONAL {
        object name clause
    }
}
", verbose_name="Object name clause") - alternativeObjectName = models.TextField( - default='', - blank=True, - help_text="Need help?
Clause that tells QLever UI the alternativename of an object (without prefixes). Qlever UI expects the following variables to be used:
  -  ?qleverui_entity: The object that we want to get the name of
  -  ?qleverui_altname: The variable that will hold the object's alternative name
Your clause should end in a dot '.' or closing bracket '}'
Your clause will be used as following:
SELECT ?qleverui_altname WHERE {
    <subject> <predicate> ?qleverui_entity
    OPTIONAL {
        alternative object name clause
    }
}
", - verbose_name="Alternative object name clause") - replacePredicates = models.TextField( default='', blank=True, @@ -159,7 +141,7 @@ class Backend(models.Model): def save(self, *args, **kwargs): # We need to replace \r because QLever can't handle them very well - for field in ('subjectName', 'predicateName', 'objectName', 'suggestSubjects', 'suggestPredicates', 'suggestObjects', 'alternativeSubjectName', 'alternativePredicateName', 'alternativeObjectName'): + for field in ('subjectName', 'predicateName', 'objectName', 'suggestSubjects', 'suggestPredicates', 'suggestObjects'): setattr(self, field, str(getattr(self, field)).replace( "\r\n", "\n").replace("\r", "\n")) super(Backend, self).save(*args, **kwargs) @@ -206,7 +188,7 @@ def predicateSuggestions(self): def entityNameQueries(self): data = {} - for field in ('subjectName', 'predicateName', 'objectName', 'suggestSubjects', 'suggestPredicates', 'suggestObjects', 'alternativeSubjectName', 'alternativePredicateName', 'alternativeObjectName'): + for field in ('subjectName', 'predicateName', 'objectName', 'suggestSubjects', 'suggestPredicates', 'suggestObjects'): data[field.upper()] = getattr(self, field) return json.dumps(data) diff --git a/backend/templates/index.html b/backend/templates/index.html index c0acf9d2..3d707c18 100644 --- a/backend/templates/index.html +++ b/backend/templates/index.html @@ -26,9 +26,6 @@ var SUBJECTNAME = ENTITYNAMERELATIONS["SUBJECTNAME"]; var PREDICATENAME = ENTITYNAMERELATIONS["PREDICATENAME"]; var OBJECTNAME = ENTITYNAMERELATIONS["OBJECTNAME"]; - var ALTERNATIVESUBJECTNAME = ENTITYNAMERELATIONS["ALTERNATIVESUBJECTNAME"]; - var ALTERNATIVEPREDICATENAME = ENTITYNAMERELATIONS["ALTERNATIVEPREDICATENAME"]; - var ALTERNATIVEOBJECTNAME = ENTITYNAMERELATIONS["ALTERNATIVEOBJECTNAME"]; var SUGGESTSUBJECTS = ENTITYNAMERELATIONS["SUGGESTSUBJECTS"]; var SUGGESTPREDICATES = ENTITYNAMERELATIONS["SUGGESTPREDICATES"]; var SUGGESTOBJECTS = ENTITYNAMERELATIONS["SUGGESTOBJECTS"]; diff --git a/resources/backend-sample.csv b/resources/backend-sample.csv index bb706b47..8620e914 100644 --- a/resources/backend-sample.csv +++ b/resources/backend-sample.csv @@ -1,4 +1,4 @@ -id,name,baseUrl,ntFilePath,ntFileLastChange,isDefault,isImporting,maxDefault,filteredLanguage,dynamicSuggestions,suggestSubjects,suggestPredicates,suggestObjects,subjectName,alternativeSubjectName,predicateName,alternativePredicateName,objectName,alternativeObjectName,replacePredicates,supportedKeywords,supportedFunctions,fillPrefixes,filterEntities +id,name,baseUrl,ntFilePath,ntFileLastChange,isDefault,isImporting,maxDefault,filteredLanguage,dynamicSuggestions,suggestSubjects,suggestPredicates,suggestObjects,subjectName,predicateName,objectName,replacePredicates,supportedKeywords,supportedFunctions,supportedPredicateSuggestions,suggestPrefixnamesForPredicates,suggestSubjectsInEmptyLine,fillPrefixes,filterEntities 9999,Wikidata Full @ Uni Freiburg,http://qlever.informatik.uni-freiburg.de/api/wikidata-full,,0,1,0,100,en,2,"SELECT ?qleverui_entity (SAMPLE(?qleverui_name) as ?qleverui_name) (SAMPLE(?qleverui_altname) as ?qleverui_altname) (SAMPLE(?qleverui_count) as ?qleverui_count) WHERE { # IF !CURRENT_WORD_EMPTY # { @@ -195,12 +195,9 @@ SELECT ?qleverui_entity (SAMPLE(?qleverui_name) as ?qleverui_name) (SAMPLE(?qlev } # ENDIF # GROUP BY ?qleverui_entity -ORDER BY DESC(?qleverui_count)",?qleverui_entity @en@ ?qleverui_name .,?qleverui_entity @en@ ?qleverui_altname .,"{ ?qleverui_claim ?qleverui_entity . +ORDER BY DESC(?qleverui_count)",?qleverui_entity @en@ ?qleverui_name .,"{ ?qleverui_claim ?qleverui_entity . ?qleverui_claim @en@ ?qleverui_name } UNION { ?qleverui_claim ?qleverui_entity . - ?qleverui_claim @en@ ?qleverui_name } .","{ ?qleverui_claim ?qleverui_entity . - ?qleverui_claim @en@ ?qleverui_altname } UNION - { ?qleverui_claim ?qleverui_entity . - ?qleverui_claim @en@ ?qleverui_altname }",?qleverui_entity @en@ ?qleverui_name .,?qleverui_entity @en@ ?qleverui_altname .," @en@ + ?qleverui_claim @en@ ?qleverui_name } .",?qleverui_entity @en@ ?qleverui_name .," @en@ @en@ - @en@","prefix, select, distinct, where, order, limit, offset, optional, by, as, having, not, textlimit, contains-entity, contains-word, filter, group, union, optional, has-predicate","asc, desc, avg, values, score, text, count, sample, min, max, average, concat, group_concat, langMatches, lang, regex, sum",1,0 + @en@","prefix, select, distinct, where, order, limit, offset, optional, by, as, having, not, textlimit, contains-entity, contains-word, filter, group, union, optional, has-predicate","asc, desc, avg, values, score, text, count, sample, min, max, average, concat, group_concat, langMatches, lang, regex, sum","ql:contains-word, ql:contains-entity",1,0,1,0