/* Part of SWISH Author: Jan Wielemaker E-mail: J.Wielemaker@cs.vu.nl WWW: http://www.swi-prolog.org Copyright (C): 2014-2018, VU University Amsterdam CWI Amsterdam All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. 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 OWNER 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. */ /** * @fileOverview * Provide the query editing facilities. * * @version 0.2.0 * @author Jan Wielemaker, J.Wielemaker@vu.nl * @requires jquery * @requires laconic * @requires editor */ define([ "jquery", "config", "preferences", "cm/lib/codemirror", "modal", "utils", "laconic", "editor" ], function($, config, preferences, CodeMirror, modal, utils) { (function($) { var pluginName = 'queryEditor'; var defaults = { maxHistoryLength: 50 }; /** @lends $.fn.queryEditor */ var methods = { /** * @param {Object} options * @param {Runner} options.runner an object that understands * run(source, query), where source and query are strings. * @param {Array.String|Function} [options.examples] called to * populate the _Examples_ menu. Must return an array of strings. * @param {Integer} [options.maxHistoryLength=50] is the max number * of entries recalled by the history menu. */ _init: function(options) { return this.each(function() { var elem = $(this); var data = $.extend({}, defaults, options); var qediv = $.el.div({class:"query"}); var tabled = tableCheckbox(data); elem.addClass("prolog-query-editor swish-event-receiver reactive-size " + "unloadable"); elem.append(qediv, $.el.div({class:"prolog-prompt"}, "?-"), $.el.div({class:"query-buttons"}, $.el.span({class:"buttons-left"}, examplesButton(data), historyButton(data), aggregateButton(data)), $.el.span({class:"buttons-right"}, tabled, runButton(data)))); function tableSelected() { return $(tabled).find("input").prop("checked"); } $(qediv).append(elem.children("textarea")) .prologEditor({ role: "query", sourceID: function() { return data.sourceID(); }, prologQuery: function(q) { elem.queryEditor('run', q, tableSelected()); } }); elem.data(pluginName, data); if ( !$(qediv).prologEditor('getSource', "query") ) { if ( typeof(data.examples) == "object" ) { if ( data.examples[0] ) $(qediv).prologEditor('setSource', data.examples[0]); } else { elem[pluginName]('setProgramEditor', $(data.editor), true); } } elem.on("current-program", function(ev, editor) { elem[pluginName]('setProgramEditor', $(editor)); }); elem.on("program-loaded", function(ev, options) { var query = options.query; if ( query != null ) { /* null: keep */ if ( query == undefined ) { if ( $(data.editor).data('prologEditor') == $(options.editor).data('prologEditor') ) { var exl = data.examples(); query = exl && exl[0] ? exl[0] : ""; } } elem.queryEditor('setQuery', query); } }); elem.on("unload", function(ev, rc) { if ( elem.closest(".swish").swish('preserve_state') ) { var state = elem[pluginName]('getState'); if ( state ) localStorage.setItem("query", JSON.stringify(state)); } }); elem.on("restore", function(ev, rc) { if ( elem[pluginName]('getQuery') == "" ) { var state; // called with explicit query // TBD: not save in this case? try { var str = localStorage.getItem("query"); if ( str ) state = JSON.parse(str); } catch(err) { } if ( state && typeof(state) == "object" ) { elem[pluginName]('setState', state); } } }); elem.on("preference", function(ev, pref) { if ( pref.name == "preserve-state" && pref.value == false ) { localStorage.removeItem("query"); } }); }); }, /** * @param {jQuery} editor has become the new current program * editor. Update the examples and re-run the query highlighting. */ setProgramEditor: function(editor, force) { var data = this.data(pluginName); if ( data.editor == editor[0] && !force ) return this; data.editor = editor[0]; if ( data.editor ) { data.examples = function() { var exl = editor.prologEditor('getExamples')||[]; var global = editor.parents(".swish").swish('examples', true)||[]; if ( $.isArray(global) ) exl.concat(global); return exl; }; if ( editor.prologEditor('isPengineSource') ) { data.source = function() { var src = editor.prologEditor('getSource', "source"); var bg = $(".background.prolog.source").text(); if ( bg ) src += '\n%@background@\n' + bg; return src; }; } else { data.source = ""; } data.sourceID = function() { return editor.prologEditor('getSourceID'); }; var exl = data.examples(); if ( exl && exl[0] && this.queryEditor('isClean') ) { this.queryEditor('setQuery', exl[0]); } else { editor.prologEditor('refreshHighlight'); } } else { data.examples = ""; } }, /** * @returns {jQuery} the associated program editor */ getProgramEditor: function() { var data = this.data(pluginName); if ( data.editor ) return $(data.editor); else return $(); }, /** * @param {Array.String} set or extend the contents of the * _Examples_ menu. * @param {Boolean} [clear=true] clear the list before adding the * new examples. */ setExamples: function(list, clear) { var ul = this.find("ul.examples"); if ( !list ) list = []; if ( clear === undefined ) clear = true; if ( clear && sameExamples(list) ) return this; /* no change */ function sameExamples(exs) { var ex0; if ( (ex0=ul.data('examples')) && ex0.length == exs.length ) { for(var i=0; i= data.maxHistoryLength ) ul.children().first().remove(); ul.append($.el.li(a=$.el.a(query))); $(a).data('time', (new Date().getTime())/1000); } return this; }, /** * @return {Array} An arrayt of strings representing the * current history. */ getHistory: function() { var ul = this.find("ul.history"); var h = []; ul.children().each(function() { var a = $(this).find("a"); h.push({ query: a.text(), time: a.data('time') }); }); return h; }, restoreHistory: function(h) { var ul = this.find("ul.history"); ul.html(""); for(var i=0; i * * @class queryEditor * @tutorial jquery-doc * @memberOf $.fn * @param {String|Object} [method] Either a method name or the jQuery * plugin initialization object. * @param [...] Zero or more arguments passed to the jQuery `method` */ $.fn.queryEditor = function(method) { if ( methods[method] ) { return methods[method] .apply(this, Array.prototype.slice.call(arguments, 1)); } else if ( typeof method === 'object' || !method ) { return methods._init.apply(this, arguments); } else { $.error('Method ' + method + ' does not exist on jQuery.' + pluginName); } }; }(jQuery)); });