/* 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. Changes by: Riccardo Zese E-mail: riccardo.zese@unife.it Copyright: 2014-2016, University of Ferrara */ /** * @fileOverview * Combine the SWISH components. * * @version 0.2.0 * @author Jan Wielemaker, J.Wielemaker@vu.nl * @requires jquery */ define(["jquery", "config", "preferences", "history", "modal", "backend", "chat", "splitter", "bootstrap", "pane", "tabbed", "notebook", "navbar", "search", "editor", "query", "runner", "term", "laconic", "login", "chatroom", "version", "d3", "c3", "svg-pan-zoom" //"class-transformer" ], function($, config, preferences, history, modal) { preferences.setDefault("semantic-highlighting", true); preferences.setDefault("emacs-keybinding", false); preferences.setDefault("new-tab", true); preferences.setDefault("ace-editor", false); preferences.setDefault("monaco-editor", false); preferences.setDefault("preserve-state", false); preferences.setDefault("auto-binding-layout", true); preferences.setInform("preserve-state", ".unloadable"); window.setupPanesOnce = false; (function($) { var pluginName = 'swish'; function glyph(name, func) { func.glyph = name; return func; } function icon(name, func) { func.typeIcon = name; return func; } var defaults = { menu: { "File": { "Save ...": glyph("cloud-upload", function() { menuBroadcast("save", "as"); }), "Info & history ...": glyph("info-sign", function() { menuBroadcast("fileInfo"); }), "Reload": glyph("refresh", function() { menuBroadcast("reload"); }), "Open recent": { type: "submenu", glyph: "paperclip", action: function(ev) { history.openRecent(ev, $(this).data('document')); }, update: history.updateRecentUL }, "Share": "--", "Follow ...": config.http.locations.follow_file_options ? glyph("eye-open", function() { menuBroadcast("follow-file"); }) : undefined, "Chat ...": icon("chat", function() { menuBroadcast("chat-about-file"); }), "Chat help room ...": icon("chathelp", function() { $("body").swish('playFile', { file: "Help.swinb", chat: 'large' }); }), "Start TogetherJS ...": icon("togetherjs", function() { $("body").swish('collaborate'); }), "Export": "--", "Download": glyph("floppy-save", function() { menuBroadcast("download"); }), "Print ...": glyph("print", function() { menuBroadcast("print"); }) }, "Edit": { "Clear messages": function() { menuBroadcast("clearMessages"); }, "Changes": "--", "View changes": function() { menuBroadcast("diff"); }, "Edit": "--", "Find (Ctrl-F)": function() { menuBroadcast("edit-command", "find"); }, "Find and replace (Shift-Ctrl-F)": function() { menuBroadcast("edit-command", "replace"); }, "Jump to line (Alt-G)": function() { menuBroadcast("edit-command", "jumpToLine"); }, "Options": "--", "Semantic highlighting": { preference: "semantic-highlighting", type: "checkbox" }, "Emacs Keybinding": { preference: "emacs-keybinding", type: "checkbox", value: "false" }, "Use ACE for unknown Files": { preference: "ace-editor", type: "checkbox", value: "false" }, "Use Monaco for some Files": { preference: "monaco-editor", type: "checkbox", value: "false" }, "Open document in new tab": { preference: "new-tab", type: "checkbox", value: "true" }, "Preserve state in browser": { preference: "preserve-state", type: "checkbox", value: "true" } }, "Examples": function(navbar, dropdown) { $("body").swish('populateExamples', navbar, dropdown); }, "Logicmoo": function(navbar, dropdown) { $("body").swish('populateExtendedExamples', navbar, dropdown, config.http.locations.swish_extended_examples + "/logicmoo"); }, "PrologMUD": function(navbar, dropdown) { $("body").swish('populateExtendedExamples', navbar, dropdown, config.http.locations.swish_extended_examples + "/prologmud"); }, "LPS": function(navbar, dropdown) { $("body").swish('populateExtendedExamples', navbar, dropdown, config.http.locations.swish_extended_examples + "/lps_corner"); }, "PFC": function(navbar, dropdown) { $("body").swish('populateExtendedExamples', navbar, dropdown, config.http.locations.swish_extended_examples + "/pfc"); }, "Aleph": function(navbar, dropdown) { $("body").swish('populateExtendedExamples', navbar, dropdown, config.http.locations.swish_extended_examples + "/aleph"); }, /* "CPLINT": function(navbar, dropdown) { $("body").swish('populateExtendedExamples', navbar, dropdown, config.http.locations.swish_extended_examples + "/learning"); }, "CPLINT-I": function(navbar, dropdown) { $("body").swish('populateExtendedExamples', navbar, dropdown, config.http.locations.swish_extended_examples + "/inference/*.swinb"); }, "CPLINT-IP": function(navbar, dropdown) { $("body").swish('populateExtendedExamples', navbar, dropdown, config.http.locations.swish_extended_examples + "/inference/*pl"); }, "Trill": function(navbar, dropdown) { $("body").swish('populateExtendedExamples', navbar, dropdown, config.http.locations.swish_extended_examples + "/trill"); }, "Phil": function(navbar, dropdown) { $("body").swish('populateExtendedExamples', navbar, dropdown, config.http.locations.swish_extended_examples + "/phil"); }, "LPS Survival": function(navbar, dropdown) { $("body").swish('populateExtendedExamples', navbar, dropdown, config.http.locations.swish_extended_examples + "/lps_corner/survival_game"); }, // "LPS Testing": function(navbar, dropdown) { // $("body").swish('populateExtendedExamples', navbar, dropdown, // config.http.locations.swish_extended_examples+"/lps_corner/forTesting"); }, // "LPS CLOUT": function(navbar, dropdown) { // $("body").swish('populateExtendedExamples', navbar, dropdown, // config.http.locations.swish_extended_examples+"/lps_corner/CLOUT_workshop"); }, "Top NB": function(navbar, dropdown) { $("body").swish('populateExtendedExamples', navbar, dropdown, config.http.locations.swish_extended_examples + "/*.swinb"); }, // "Extended Examples": function(navbar, dropdown) { // $("body").swish('populateExtendedExamples', navbar, dropdown, // config.http.locations.swish_extended_examples); }, */ "Help": function(navbar, dropdown) { $("body").swish('populateHelp', navbar, dropdown); }, "Extensions Menu": { "Help on cplint...": function() { menuBroadcast("help", { file: "help-cplint.html" }); }, "Pldoc on cplint...": function() { var win = window.open("http://cplint.lamping.unife.it/pldoc/doc/home/trill/lib/swipl/pack/cplint/prolog/", '_blank'); win.focus(); }, "Help on aleph...": function() { menuBroadcast("help", { file: "help-aleph.html" }); }, "PLP Tutorial": function() { var win = window.open("http://ds.ing.unife.it/~gcota/plptutorial/", '_blank'); win.focus(); //console.log("click on tutorial"); //methods.playURL.call($("body"), {url:"/tutorial/tutorial.swinb"}); }, } } }; // defaults; /** @lends $.fn.swish */ var methods = { /** * Initialise SWISH on the page. At this moment, a page can only * contain one SWISH application and swish is normally initialised * on the body. This might change. * @example $("body").swish(); * {Object} options * {Boolean} options.show_beware If `true`, show a dialogue box * telling this is a limited version. */ _init: function(options) { if(!window.setupPanesOnce) { swishLogo(); setupModal(); setupPanes(); setupResize(); setupUnload(); // aboutLink(); // $("#search").search(); } options = options || {}; this.addClass("swish"); return this.each(function() { var elem = $(this); var data = {}; /* private data */ $("#navbar").navbar(defaults.menu); $("#login").login(); var editor = $(".prolog-editor").prologEditor({ save: true }); data.runner = $(".prolog-runners").prologRunners(); data.query = $(".prolog-query").queryEditor({ source: function() { return elem.swish('prologSource'); }, sourceID: function() { return editor.prologEditor('getSourceID'); }, examples: elem.swish('examples'), runner: data.runner, editor: editor[0] }); elem.data(pluginName, data); /* store with element */ data.restoring = true; $(".notebook").notebook(); if (options.show_beware && !(swish.option && swish.option.show_beware == false)) menuBroadcast("help", { file: "beware.html", notagain: "beware" }); if (window.location.href.indexOf("&togetherjs=") > 0) elem.swish('collaborate'); $("#chat").chat(''); $("#broadcast-bell") .chatbell({ empty_title: "Click to open chat" }); $("#chat-menu").on("click", "a", function(ev) { var a = $(ev.target).closest("a"); switch (a.data('action')) { case 'chat-shared': $("body").swish('playFile', { file: config.swish.hangout, chat: 'large' }); break; case 'chat-about-file': menuBroadcast("chat-about-file"); } }); setInterval(function() { $(".each-minute").trigger("minute"); }, 60000); if (elem[pluginName]('preserve_state')) { $(".unloadable").trigger("restore"); } delete data.restoring; elem[pluginName]('runDelayedRestore'); $().version('checkForUpdates'); }); }, /** * @return {Boolean} `true` when we should save and restore * the state to the browser local store. */ preserve_state: function() { var swish = this; if(swish.option == undefined) return false; if (swish.option.preserve_state == false) return false; if (preferences.getVal("preserve-state") == false) return false; function getQueryVariable(variable) { var query = window.location.search.substring(1); var vars = query.split('&'); for (var i = 0; i < vars.length; i++) { var pair = vars[i].split('='); if (decodeURIComponent(pair[0]) == variable) { return decodeURIComponent(pair[1]); } } } if (getQueryVariable("restore") == "false") return false; return true; }, afterRestore: function(f) { var data = this.data("swish"); if (data.after_restore) data.after_restore.push(f); else data.after_restore = [f]; return this; }, runDelayedRestore: function() { var swish = this; var data = this.data("swish"); if (data.after_restore) { var f; while ((f = data.after_restore.pop())) f.call(swish); } return this; }, /** * Trigger a global event in SWISH. Currently defined events are: * * - `help` -- show a modal help window * - `source` -- load a new source * - `saveProgram` -- save the current program * * This method triggers all elements of class * `swish-event-receiver`. * * @param {String} name is the name of the trigger. * @param {Object|null} data provides additional data for the event. */ trigger: function(name, data) { menuBroadcast(name, data); return this; }, /** * Play a file from the webstore, loading it through ajax * @param {String|Object} options If a string, the name * of the file in the web storage * @param {String} options.file is the name of the file in the web * storage * @param {Number} [options.line] is the initial line number * @param {RegEx} [options.regex] search to highlight * @param {Boolean} [options.showAllMatches] Show other matches on * page. * @param {Boolean} [options.newTab] if `true`, open the file in * a new tab. * @param {Boolean} [options.noHistory] if `true`, do not push the * new document to the history. * @param {Object} [options.prompt] provided for trace events. Must * be used to highlight the Prolog port at the indicated location. */ playFile: function(options) { var elem = this; if (typeof(options) == "string") options = { file: options }; var existing = this.find(".storage").storage('match', options); if (existing && existing.storage('expose', "Already open")) return this; /* FIXME: go to line */ var url = config.http.locations.web_storage + options.file; $.ajax({ url: url, type: "GET", data: { format: "json" }, success: function(reply) { reply.url = url; reply.st_type = "gitty"; function copyAttrs(names) { for (var i = 0; i < names.length; i++) { var name = names[i]; if (options[name]) reply[name] = options[name]; } } copyAttrs(["line", "regex", "showAllMatches", "newTab", "noHistory", "prompt", "chat" ]); elem.swish('setSource', reply); }, error: function(jqXHR) { // modal.ajaxError(jqXHR); } }); return this; }, /** * Load file from a URL. This fetches the data from the URL and * broadcasts a `"source"` event that is normally picked up by * the tabbed pane. * @param {Object} options * @param {String} options.url URL to load. * @param {Integer} [options.line] Line to go to. * @param {Regex} [options.search] Text searched for. */ playURL: function(options) { var elem = this; var existing = this.find(".storage").storage('match', options); if (existing && existing.storage('expose', "Already open")) return this; /* FIXME: go to line */ //debugger; $.ajax({ url: options.url, type: "GET", data: { format: "json" }, success: function(source) { var msg; if (typeof(source) == "string") { msg = { data: source }; msg.st_type = "external"; } else if (typeof(source) == "object" && typeof(source.data) == "string") { msg = source; msg.st_type = "filesys"; } else { alert("Invalid data"); return; } msg.url = options.url; function copyAttrs(names) { for (var i = 0; i < names.length; i++) { var name = names[i]; if (options[name]) msg[name] = options[name]; } } copyAttrs(["line", "regex", "showAllMatches", "newTab", "noHistory", "prompt" ]); elem.swish('setSource', msg); }, error: function(jqXHR) { // modal.ajaxError(jqXHR); } }); }, /** * Open a source. If we are in fullscreen mode and the current * object cannot be opened by the current fullscreen node, we * leave fullscreen mode. Called by playFile and playURL. */ setSource: function(src) { var st = this.swish('isFullscreen'); if (!(st && st.storage('setSource', src))) { if (st) this.swish('exitFullscreen'); this.find(".tabbed").tabbed('tabFromSource', src); } return this; }, /** * @param {Object} ex * @param {String} ex.title is the title of the example * @param {String} ex.file is the (file) name of the example * @param {String} ex.href is the URL from which to download the * program. * @returns {Function|String} function that loads an example */ openExampleFunction: function(ex) { var swish = this; if (ex.type == "divider") { return "--"; } else if (ex.type == "store") { return function() { methods.playFile.call(swish, ex.file); }; } else { return function() { methods.playURL.call(swish, { url: ex.href }); }; } }, /** * Populate the examples dropdown of the navigation bar. This * method is used by the navigation bar initialization. * @param {Object} navbar is the navigation bar * @param {Object} dropdown is the examples dropdown */ populateExamples: function(navbar, dropdown) { var that = this; that.off("examples-changed") .on("examples-changed", function() { $("#navbar").navbar('clearDropdown', dropdown); that.swish('populateExtendedExamples', navbar, dropdown, config.http.locations.swish_examples); }); $("body").swish('populateExtendedExamples', navbar, dropdown, config.http.locations.swish_examples); return this; }, /** * populateExtendedExamples */ populateExtendedExamples: function(navbar, dropdown, where) { var that = this; $.ajax(where, { dataType: "json", success: function(data) { for (var i = 0; i < data.length; i++) { var ex = data[i]; var title; var options; if (ex.type == "group" || ex.type == "submenu") { //debugger; title = ex.title || ex.file || ex.href; options = {}; options.action = null; options.type = "submenu"; options.items = ["a", "b", "c"]; if(ex.items !== undefined) { options.items = ex.items; } options.typeIcon = "folder"; $("#navbar").navbar('appendDropdown', dropdown, title, options); continue; /*