UNPKG

yasgui

Version:

Yet Another SPARQL GUI

466 lines (426 loc) 14.4 kB
"use strict"; var $ = require("jquery"), EventEmitter = require("events").EventEmitter, utils = require("yasgui-utils"), imgs = require("./imgs.js"), stories = require("./stories.js"), md5 = require("blueimp-md5"); require("./jquery/extendJquery.js"); //extend some own jquery plugins /** * set this dynamically on instantiation: this YASR setting is dependent on the corsProxy yasgui setting */ var setYasrOptions = function(options) { var corsLiHtml = 'Endpoint is not <a href="http://enable-cors.org/" target="_blank">CORS-enabled</a>'; if (options.api.corsProxy) { //We have a proxy. only possible reason CORS is still an issue, is when endpoints runs on localhost, different port, and cors enabled corsLiHtml = 'Endpoint is not accessible from the YASGUI server and website, and the endpoint is not <a href="http://enable-cors.org/" target="_blank">CORS-enabled</a>'; } module.exports.YASR.plugins.error.defaults.corsMessage = $("<div>") .append($("<p>").append("Unable to get response from endpoint. Possible reasons:")) .append( $("<ul>") .append($("<li>").text("Incorrect endpoint URL")) .append($("<li>").text("Endpoint is down")) .append($("<li>").html(corsLiHtml)) ); }; var YASGUI = function(parent, options) { EventEmitter.call(this); var yasgui = this; yasgui.wrapperElement = $('<div class="yasgui"></div>').appendTo($(parent)); yasgui.options = $.extend(true, {}, module.exports.defaults, options); setYasrOptions(yasgui.options); yasgui.history = []; yasgui.persistencyPrefix = null; if (yasgui.options.persistencyPrefix) { yasgui.persistencyPrefix = typeof yasgui.options.persistencyPrefix == "function" ? yasgui.options.persistencyPrefix(yasgui) : yasgui.options.persistencyPrefix; yasgui.persistencyPrefix = md5(yasgui.persistencyPrefix); } if (yasgui.persistencyPrefix) { var histFromStorage = utils.storage.get(yasgui.persistencyPrefix + "history"); if (histFromStorage) yasgui.history = histFromStorage; } yasgui.store = function() { if (yasgui.persistentOptions) { utils.storage.set(yasgui.persistencyPrefix, yasgui.persistentOptions, null, yasgui.options.onQuotaExceeded); } }; var getSettingsFromStorage = function() { var settings = utils.storage.get(yasgui.persistencyPrefix); if (!settings) settings = {}; //initialize blank. Default vals will be set as we go return settings; }; yasgui.persistentOptions = getSettingsFromStorage(); if (yasgui.persistentOptions.tabManager) yasgui.persistentOptions = yasgui.persistentOptions.tabManager; //for backwards compatability var persistentOptions = yasgui.persistentOptions; //tab object (containing e.g. yasqe/yasr) yasgui.tabs = {}; //the actual tabs parent containing the ul of tab buttons var $tabsParent; //contains the tabs and panes var $tabPanel = null; //context menu for the tab context menu var $contextMenu = null; var getTabName = function(name, i) { if (!name) name = "Query"; if (!i) i = 0; var fullName = name + (i > 0 ? " " + i : ""); if (tabNameTaken(fullName)) fullName = getTabName(name, i + 1); return fullName; }; var tabNameTaken = function(name) { for (var tabId in yasgui.tabs) { if (yasgui.tabs[tabId].persistentOptions.name == name) { return true; } } return false; }; var getRandomId = function() { return Math.random().toString(36).substring(7); }; var getTabInputEl = function() { return $('<div><input type="text"></div>').keydown(function(e) { if (e.which == 27 || e.keyCode == 27) { //esc $(this).closest("li").removeClass("rename"); } else if (e.which == 13 || e.keyCode == 13) { //enter storeRename($(this).closest("li")); } }); }; var renameStart = function(tabEl) { var val = tabEl.find("span").text(); tabEl.addClass("rename"); tabEl.find("input").val(val).focus(); tabEl.onOutsideClick(function() { storeRename(tabEl); }); }; var storeRename = function($liEl, newTitle) { var tabId = $liEl.find('a[role="tab"]').attr("aria-controls"); var val = newTitle || $liEl.find("input").val(); $liEl.find("span").text(val); persistentOptions.tabs[tabId].name = val; yasgui.store(); $liEl.removeClass("rename"); }; var renameTab = function(id, newTitle) { storeRename($tabsParent.find('a[role="tab"][aria-controls=' + id + ']').parent(), newTitle) } yasgui.renameTab = renameTab; yasgui.init = function() { //tab panel contains tabs and panes $tabPanel = $("<div>", { role: "tabpanel" }).appendTo(yasgui.wrapperElement); //init tabs $tabsParent = $("<ul>", { class: "nav nav-tabs mainTabs", role: "tablist" }).appendTo($tabPanel); yasgui.$tabsParent = $tabsParent; //init add button var $addTab = $("<a>", { role: "addTab" }) .click(function(e) { addTab(); }) .text("+"); $tabsParent.append( $("<li>", { role: "presentation" }).append($addTab) ); //init panes yasgui.$tabPanesParent = $("<div>", { class: "tab-content" }).appendTo($tabPanel); if (!persistentOptions || $.isEmptyObject(persistentOptions)) { //ah, this is on first load. initialize some stuff persistentOptions = { tabOrder: [], tabs: {}, selected: null }; yasgui.options.tabs.forEach(function(tab) { var id = getRandomId(); if (!persistentOptions.selected) persistentOptions.selected = id; persistentOptions.tabOrder.push(id); persistentOptions.tabs[id] = $.extend( true, {}, { id: id }, tab ); }); yasgui.persistentOptions = persistentOptions; yasgui.store(); } var optionsFromUrl = require("./shareLink.js").getOptionsFromUrl(); if (optionsFromUrl) { //hmm, we have options from the url. make sure we initialize everything using this tab //the one thing we don't have is the ID. generate it. var tabId = getRandomId(); optionsFromUrl.id = tabId; persistentOptions.tabs[tabId] = optionsFromUrl; persistentOptions.tabOrder.push(tabId); persistentOptions.selected = tabId; yasgui.once("ready", function() { if (persistentOptions.tabs[tabId].yasr.outputSettings) { var plugin = yasgui.current().yasr.plugins[persistentOptions.tabs[tabId].yasr.output]; if (plugin.options) { $.extend(plugin.options, persistentOptions.tabs[tabId].yasr.outputSettings); } delete persistentOptions.tabs[tabId]["yasr"]["outputSettings"]; } yasgui.current().query(); }); } persistentOptions.tabOrder.forEach(addTab); $tabsParent.sortable({ placeholder: "tab-sortable-highlight", items: 'li:has([data-toggle="tab"])', //don't allow sorting after ('+') icon forcePlaceholderSize: true, update: function() { var newTabOrder = []; $tabsParent.find('a[data-toggle="tab"]').each(function() { newTabOrder.push($(this).attr("aria-controls")); }); persistentOptions.tabOrder = newTabOrder; yasgui.store(); } }); //Add context menu $contextMenu = $("<div>", { class: "tabDropDown" }).appendTo(yasgui.wrapperElement); var $contextMenuList = $("<ul>", { class: "dropdown-menu", role: "menu" }).appendTo($contextMenu); var addMenuItem = function(name, onClick) { var $listItem = $("<li>", { role: "presentation" }).appendTo($contextMenuList); if (name) { $listItem .append( $("<a>", { role: "menuitem", href: "#" }).text(name) ) .click(function(event) { $contextMenu.hide(); event.preventDefault(); if (onClick) onClick($contextMenu.attr("target-tab")); }); } else { $listItem.addClass("divider"); } }; addMenuItem("Add new Tab", function(tabId) { addTab(); }); addMenuItem("Rename", function(tabId) { renameStart($tabsParent.find('a[href="#' + tabId + '"]').parent()); }); addMenuItem("Copy", function(tabId) { var newTabId = getRandomId(); var copiedSettings = $.extend(true, {}, persistentOptions.tabs[tabId]); copiedSettings.id = newTabId; persistentOptions.tabs[newTabId] = copiedSettings; addTab(newTabId); selectTab(newTabId); }); addMenuItem(); addMenuItem("Close", closeTab); addMenuItem("Close others", function(tabId) { $tabsParent.find('a[role="tab"]').each(function() { var currentId = $(this).attr("aria-controls"); if (currentId != tabId) closeTab(currentId); }); }); addMenuItem("Close all", function() { $tabsParent.find('a[role="tab"]').each(function() { closeTab($(this).attr("aria-controls")); }); }); }; var selectTab = function(id) { $tabsParent.find('a[aria-controls="' + id + '"]').tab("show"); return yasgui.current(); }; yasgui.selectTab = selectTab; var closeTab = function(id) { /** * cleanup local storage */ yasgui.tabs[id].destroy(); /**cleanup variables**/ delete yasgui.tabs[id]; delete persistentOptions.tabs[id]; var orderIndex = persistentOptions.tabOrder.indexOf(id); if (orderIndex > -1) persistentOptions.tabOrder.splice(orderIndex, 1); /** * select new tab */ var newSelectedIndex = null; if (persistentOptions.tabOrder[orderIndex]) { //use the tab now in position of the old one newSelectedIndex = orderIndex; } else if (persistentOptions.tabOrder[orderIndex - 1]) { //use the tab in the previous position newSelectedIndex = orderIndex - 1; } if (newSelectedIndex !== null) selectTab(persistentOptions.tabOrder[newSelectedIndex]); /** * cleanup dom */ $tabsParent.find('a[href="#' + id + '"]').closest("li").remove(); $("#" + id).remove(); yasgui.store(); return yasgui.current(); }; yasgui.closeTab = closeTab; var addTab = function(tabId) { var newItem = !tabId; if (!tabId) tabId = getRandomId(); if (!("tabs" in persistentOptions)) persistentOptions.tabs = {}; var name = null; if (persistentOptions.tabs[tabId] && persistentOptions.tabs[tabId].name) { name = persistentOptions.tabs[tabId].name; } if (!name) name = getTabName(); //Initialize new tab with endpoint from currently selected tab (if there is one) var endpoint = yasgui.options.endpoint; if (!endpoint && yasgui.current() && yasgui.current().getEndpoint()) { endpoint = yasgui.current().getEndpoint(); } //first add tab var $tabToggle = $("<a>", { href: "#" + tabId, "aria-controls": tabId, role: "tab", "data-toggle": "tab" }) .click(function(e) { e.preventDefault(); $(this).tab("show"); if (yasgui.tabs[tabId].yasqe) yasgui.tabs[tabId].yasqe.refresh(); }) .on("shown.bs.tab", function(e) { persistentOptions.selected = $(this).attr("aria-controls"); yasgui.tabs[tabId].onShow(); yasgui.store(); }) .append($("<div>", { class: "loader" })) .append($("<span>").text(name)) .append( $("<button>", { class: "close", type: "button" }) .text("x") .click(function() { closeTab(tabId); }) ); var $tabItem = $("<li>", { role: "presentation" }) .append($tabToggle) .append(getTabInputEl()) .dblclick(function() { var el = $(this); renameStart(el); }) .mousedown(function(e) { if (e.which == 2) { //middle Click closeTab(tabId); } }) .bind("contextmenu", function(e) { e.preventDefault(); $contextMenu .show() .onOutsideClick( function() { $contextMenu.hide(); }, { allowedElements: $(this).closest("li") } ) .addClass("open") .attr("target-tab", $tabItem.find('a[role="tab"]').attr("aria-controls")) .position({ my: "left top-3", at: "left bottom", of: $(this) }); }); $tabsParent.find('li:has(a[role="addTab"])').before($tabItem); if (newItem) persistentOptions.tabOrder.push(tabId); var Tab = require("./tab.js"); var options = { id: tabId, name: name, yasqe: yasgui.options.yasqe, yasr: yasgui.options.yasr }; if (endpoint) options.yasqe = { sparql: { endpoint: endpoint } }; yasgui.tabs[tabId] = new Tab(yasgui, options); if (newItem || persistentOptions.selected == tabId) { yasgui.tabs[tabId].beforeShow(); $tabToggle.tab("show"); } return yasgui.tabs[tabId]; }; yasgui.current = function() { return yasgui.tabs[persistentOptions.selected]; }; yasgui.addTab = addTab; yasgui.init(); yasgui.tracker = require("./tracker.js")(yasgui); yasgui.emit("ready"); return yasgui; }; YASGUI.prototype = new EventEmitter(); module.exports = function(parent, options) { return new YASGUI(parent, options); }; module.exports.sparqlStories = stories; module.exports.stories = stories; module.exports.shouldResetStorage = function() { return document.location.search.substring(1).split("&").indexOf("_resetYasgui") >= 0; }; //Before we start initializing, check whether we need to reset our storage layer if (module.exports.shouldResetStorage()) { utils.storage.removeAll(); } module.exports.YASQE = require("./yasqe.js"); module.exports.YASR = require("./yasr.js"); module.exports.version = { YASGUI: require("../package.json").version, jquery: $.fn.jquery, "yasgui-utils": require("yasgui-utils").version, YASQE: module.exports.YASQE.version, YASR: module.exports.YASR.version }; module.exports.$ = $; module.exports.defaults = require("./defaults.js");