PageRenderTime 76ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/facete-client/src/main/webapp/resources/js/org/aksw/ssb/app/controllers/AppController.js

https://github.com/GeoKnow/Facete
JavaScript | 1897 lines | 675 code | 535 blank | 687 comment | 47 complexity | 84601cc67f7f14ef2da08268ae2f6373 MD5 | raw file
  1. (function($) {
  2. /*
  3. * Disable Backbone sync
  4. */
  5. Backbone.sync = function(method, model, options) {
  6. options.success();
  7. };
  8. var sparql = Namespace("org.aksw.ssb.sparql.syntax");
  9. var facets = Namespace("org.aksw.ssb.facets");
  10. var qt = Namespace("org.aksw.ssb.collections.QuadTree");
  11. var qtm = Namespace("org.aksw.ssb.collections.QuadTreeModel");
  12. var qtc = Namespace("org.aksw.ssb.collections.QuadTreeCache");
  13. var geo = Namespace("org.aksw.ssb.vocabs.wgs84");
  14. var geovocab = Namespace("org.aksw.ssb.vocabs.geovocab");
  15. var appvocab = Namespace("org.aksw.ssb.vocabs.appvocab");
  16. var rdf = Namespace("org.aksw.ssb.vocabs.rdf");
  17. var rdfs = Namespace("org.aksw.ssb.vocabs.rdfs");
  18. var utils = Namespace("org.aksw.ssb.utils");
  19. // FIXME get rid of labelUtils references and replace with utils
  20. var labelUtils = Namespace("org.aksw.ssb.utils");
  21. var queryUtils = Namespace("org.aksw.ssb.facets.QueryUtils");
  22. var facetbox = Namespace("org.aksw.ssb.widgets.facetbox");
  23. var widgets = Namespace("org.aksw.ssb.widgets");
  24. var collections = Namespace("org.aksw.ssb.collections");
  25. var config = Namespace("org.aksw.ssb.config");
  26. var ns = Namespace("org.aksw.ssb.app.controllers");
  27. /**
  28. * A model and corresponding collection for the instances shown on the map.
  29. *
  30. */
  31. ns.ModelInstance = Backbone.Model.extend({
  32. id: "",
  33. label: ""
  34. });
  35. ns.CollectionInstance = Backbone.Collection.extend({
  36. model: ns.ModelInstance
  37. });
  38. ns.ConstraintModel = Backbone.Model.extend({
  39. defaults: {
  40. value: null
  41. /*label: "" // FIXME As there could be many ways for crafting constraint labels,
  42. //associating a label only makes sense for view-models;*/
  43. }
  44. });
  45. ns.ConstraintCollection = Backbone.Collection.extend({
  46. model: ns.ConstraintModel
  47. });
  48. /**
  49. * A view state consists of the visible bounds, the corresponding
  50. * (quad tree) nodes TODO: and the cache?
  51. *
  52. * @param cache
  53. * @returns {ns.ViewState}
  54. */
  55. ns.ViewState = function(nodes, bounds, visibleGeoms) {
  56. this.nodes = nodes;
  57. this.bounds = bounds; //null; //new qt.Bounds(-9999, -9998, -9999, -9998);
  58. this.visibleGeoms = visibleGeoms ? visibleGeoms : [];
  59. };
  60. /*
  61. ns.QueryCacheGeo = function(sparqlService, baseQuery, geoConstraint) {
  62. this.sparqlService = sparqlService;
  63. this.baseQuery = baseQuery;
  64. this.geoConstraint = geoConstraint;
  65. this.quadTreeModel = new collections.QuadTreeModel();
  66. };
  67. ns.QueryCacheGeo.prototype.execute = function(bounds, callback) {
  68. };
  69. */
  70. /**
  71. * The main class for the Spatial Semantic Browsing Widgets.
  72. * Holds references to model classes, and can initialize the controller.
  73. *
  74. *
  75. * @returns {AppController}
  76. */
  77. ns.AppController = function(options) {
  78. this.sparqlService = null;
  79. this.options = options;
  80. /*
  81. * Backend configuration
  82. */
  83. // The label for referring to the base of navigation.
  84. this.rootNavigationLabel = "home";
  85. var conf = options.queryGenerator;
  86. var queryGenerator = new widgets.QueryGenerator(conf.concept, conf.navigationPath, null, conf.constraints, conf.pathManager);
  87. this.queryGeneratorGeo = new ns.QueryGeneratorGeo(queryGenerator, conf.geoConstraintFactory);
  88. //this.queryGenerator = new ns.QueryGenerator(options.queryGenerator);
  89. this.queryFactory = null;
  90. this.selection = new collections.Set();
  91. // The currently selected feature
  92. // FIXME Change to something like "selectedResource", so we can track
  93. // the active feature between mapEvents (features get destroyed on map events)
  94. //this.selectedFeature = undefined;
  95. // The active language
  96. // TODO Make sure this can be removed.
  97. this.activeLanguage = "fr";
  98. //this.quadTreeModel = null;
  99. this.nodeToLabel = new collections.Map();
  100. this.nodeToTypes = new collections.MultiMap();
  101. this.nodeToFeature = new collections.Map();
  102. this.schemaIcons = new MapCollection();
  103. // Reference to the OpenLayers map
  104. this.mapWidget = null;
  105. this.map = null;
  106. this.instanceWidget = null;
  107. //this.geomToId = new facets.MultiMap();
  108. this.hoveredItems = [];
  109. // Maps prefixes to DescribeService's that provide additional information about
  110. // resources
  111. this.prefixToService = {};
  112. // query cache; maps a base query to a quad tree model
  113. this.hashToCache = {};
  114. this.viewState = new ns.ViewState();
  115. // A wrapper for a rdfquery databank which keeps track of how often a triple was added
  116. this.multiGraph = new collections.MultiGraph();
  117. this.labelFetcher = null;
  118. this.queryCacheFactory = null;
  119. this.abbreviator = new utils.Abbreviator();
  120. // Map resources to stuff like selected, or hovered, so we can
  121. // style markers in corresponding colors and sizes
  122. this.resourceState = {};
  123. };
  124. /**
  125. * Save the current application state to a JSON object
  126. *
  127. */
  128. ns.AppController.prototype.saveState = function() {
  129. var result = {
  130. map: this.mapWidget.saveState()
  131. };
  132. return result;
  133. };
  134. /**
  135. * Load an application state from an JSON object
  136. *
  137. */
  138. ns.AppController.prototype.loadState = function(state) {
  139. this.mapWidget.loadState(state.map);
  140. //this.doLayout();
  141. //this.repaint();
  142. };
  143. ns.AppController.prototype.doLayout = function() {
  144. $(window).resize();
  145. };
  146. ns.AppController.prototype.init = function() {
  147. //var self = this;
  148. this.initWidgets();
  149. this.initEvents();
  150. var self = this;
  151. // DEBUG/TESTING
  152. var test = $$({}, "<div style='position: absolute; left: 60px; top: 5px; z-index: 1000;'><button>PermaLink</button></div>", {
  153. 'click button': function() {
  154. var baseUrl = location.href;
  155. // cut off any hash string
  156. var hashString = "";
  157. var hashStringStart = baseUrl.indexOf("#");
  158. if(hashStringStart >= 0) {
  159. hashString = baseUrl.substring(hashStringStart);
  160. baseUrl = baseUrl.substring(0, hashStringStart);
  161. }
  162. // cut off the query string
  163. var queryStringStart = baseUrl.indexOf("?");
  164. if(queryStringStart >= 0) {
  165. baseUrl = baseUrl.substring(0, queryStringStart);
  166. }
  167. //var stateArg = $.param(self.saveState());
  168. var stateStr = JSON.stringify(self.saveState());
  169. var stateArg = encodeURIComponent(stateStr);
  170. var url = baseUrl + "?state=" + stateArg + hashString;
  171. //alert("State: " + url + "?state=" + stateArg);
  172. window.prompt("Copy to clipboard", url);
  173. }
  174. });
  175. $$.document.append(test, "#map");
  176. var homePath = new facets.Path(); //new facets.Breadcrumb.fromString(this.queryGenerator.pathManager, "");
  177. this.setNavigationPath(homePath);
  178. };
  179. ns.AppController.prototype.updateConstraints = function() {
  180. var self = this;
  181. var cs = this.queryGeneratorGeo.getConstraints();
  182. cs.clear();
  183. this.constraints.each(function(item) {
  184. var c = item.get("value");
  185. //alert("" + typeof(item) + " " + JSON.stringify(item));
  186. //alert("" + item.value);
  187. //console.log("dammit", item);
  188. cs.add(c);
  189. });
  190. //self.constraintWidget.refresh();
  191. self.repaint();
  192. };
  193. ns.AppController.prototype.initWidgets = function() {
  194. // Initialize the widgets
  195. $("#map").ssb_map({
  196. nodeToPos: this.nodeToPos,
  197. nodeToFeature: this.nodeToFeature,
  198. wayToFeature: this.wayToFeature,
  199. instanceToLabel: this.nodeToLabel,
  200. nodeToTypes: this.nodeToTypes,
  201. schemaIcons: this.schemaIcons
  202. });
  203. /*
  204. $("#instances").ssb_instances({
  205. instanceToLabel: this.nodeToLabel,
  206. instanceToType: this.nodeToTypes,
  207. schemaIcons: this.schemaIcons
  208. });
  209. this.instanceWidget = $("#instances").data("ssb_instances");
  210. */
  211. /*
  212. $("#facets").ssb_facets({
  213. schemaIcons: this.schemaIcons,
  214. schemaLabels: this.schemaLabels,
  215. classHierarchy: this.classHierarchy,
  216. selection: this.selection
  217. });
  218. */
  219. //$("#facts").ssb_facts({});
  220. //var describer = new widgets.Describer(this.sparqlService);
  221. //this.factBox = widgets.createResourceWidget(this.sparqlService);
  222. //$$.document.append(this.factBox, "#box-facts");
  223. //this.factBox.controller.setNodes([sparql.Node.uri("http://fintrans.publicdata.eu/ec/ontology/beneficiary")]);
  224. //$("#facts").append(this.factBox.view());
  225. //$("#browsebox").ssb_browsebox({});
  226. this.mapWidget = $("#map").data("ssb_map");
  227. this.map = this.mapWidget.map;
  228. /*
  229. var self = this;
  230. $(window).resize(function() {
  231. var container = $("#map");
  232. self.map.size(container.width(), container.height());
  233. });
  234. */
  235. //this.facts = $("#facts").data("ssb_facts");
  236. // TODO: Do not depend directly on map, but on a "visible area"
  237. $("#searchResults").ssb_search({map: this.map});
  238. // Facet box
  239. var queryGeneratorGeo = this.queryGeneratorGeo;
  240. var constraints = queryGeneratorGeo.getConstraints();
  241. //var facetConfig = new facetbox.FacetConfig(1001, 10001);
  242. this.facetConfig = new facetbox.FacetConfig(1001, null);
  243. //var baseBreadcrumb = new facets.Breadcrumb(queryGenerator.pathManager);
  244. //this.facetState = new facetbox.FacetState(this.facetConfig, queryGenerator.getInferredDriver(), basePath);
  245. var basePath = new facets.Path();
  246. //this.facetState = new facetbox.FacetState(this.queryGenerator, basePath);
  247. //var facetBoxBackend = new facetbox.FacetValueBackendSparql(this.sparqlService, this.facetConfig, this.queryGenerator); //this.labelFetcher);
  248. var self = this;
  249. $(config.EventBus).on("resourcesModified", function(resources) {
  250. //setTimeout((function() {
  251. //self.mapWidget.redraw();
  252. self.factBox.controller.redraw();
  253. self.repaint();
  254. //}), 500);
  255. });
  256. this.breadcrumbWidget = widgets.createBreadcrumbWidget({
  257. onNavigate: function(path) {
  258. self.setNavigationPath(path);
  259. }
  260. });
  261. $$.document.append(this.breadcrumbWidget, "#ssb-breadcrumb");
  262. var callbacks = {
  263. onMoveTo: function(path) {
  264. self.setNavigationPath(path);
  265. }
  266. };
  267. /*
  268. var listWidget = widgets.createExecutorList(executorModel, widgets.checkItemFactory, this.labelFetcher);
  269. listWidget.getListWidget().bind("click", function(ev, payload) {
  270. alert(payload.checked + " " + payload.item.model.get("label"));
  271. });
  272. $$.document.append(listWidget, $("#ssb-graph-selection"));
  273. listWidget.getListWidget().refresh();
  274. */
  275. //config, queryGenerator, basePath, backend, callbacks
  276. //this.facetBox = $$(facetbox.FacetBox); //widgets.createListWidget2(ns.FacetSwitcherItemFactory, ns.hackId);
  277. /*
  278. * Instances
  279. */
  280. this.visibleInstances = new ns.CollectionInstance();
  281. this.visibleInstances.bind("add", function(model) {
  282. //alert("yay");
  283. });
  284. var InstanceListItemView = widgets.ItemViewLabel.extend({
  285. events: {
  286. 'click span': function(event) {
  287. self.showFeatureDetails(this.model.get("id"));
  288. }
  289. }
  290. });
  291. var instanceListView = new widgets.ListView({
  292. el: $("#tabs-content-instances"),
  293. attributes: {style: {'list-style': 'none'}},
  294. collection: this.visibleInstances,
  295. itemRenderer: new widgets.ItemRendererBackbone(InstanceListItemView)
  296. });
  297. var mapSyncView = new widgets.ItemViewMapMarker({
  298. //el: $("#tabs-content-instances"),
  299. //attributes: {style: {'list-style': 'none'}},
  300. mapWidget: self.mapWidget,
  301. collection: this.visibleInstances
  302. //itemRenderer: new widgets.ItemRendererBackbone(InstanceListItemView)
  303. });
  304. /*
  305. * Constraints
  306. */
  307. this.constraintSelections = new widgets.SelectionCollection();
  308. this.constraints = new ns.ConstraintCollection();
  309. // Fetch labels
  310. var constraintTextBuilder = new widgets.ConstraintTextBuilder(this.labelFetcher);
  311. // TODO: The constraint text builder should operate on the collection, not individual models
  312. this.constraints.bind("add", function(model) {
  313. constraint = model.get("value");
  314. var task = constraintTextBuilder.fetchSimpleText(constraint);
  315. $.when(task).then(function(labelStr) {
  316. model.set({simpleLabel: labelStr});
  317. }).fail(function() {
  318. console.error("Error fetching label for model: ", model);
  319. //alert("Error fetching label for " + model.get("id"));
  320. });
  321. });
  322. this.constraints.bind("add", function(model) {
  323. var id = model.id;
  324. self.constraintSelections.add(new widgets.SelectionModel({id: id, isSelected: true}));
  325. self.updateConstraints();
  326. });
  327. this.constraints.bind("remove", function(model) {
  328. var id = model.id;
  329. var model = self.constraintSelections.get(id);
  330. if(model) {
  331. model.destroy();
  332. }
  333. self.updateConstraints();
  334. });
  335. /*
  336. //this.col = new SelectionModel();
  337. this.col.bind("add", function(item) {
  338. alert("" + item);
  339. });
  340. console.log("Sigh", this.col);
  341. this.col.add(new SelectionItem({isSelected: true}));
  342. this.col.add(new SelectionItem());
  343. */
  344. //var tmpSelMod = {};
  345. this.facetBox = facetbox.createFacetBox(this.constraintSelections); //tmpSelMod); //this.constraintSelections);
  346. this.facetBox.view.$().autoHeight();
  347. this.facetBox.bind("clickFacetValues", function(ev, payload) {
  348. console.log("Facet value clicked. PAYLOAD", payload.model);
  349. var path = payload.model.get("path");
  350. //var relativePath = payload.model.get("path");
  351. //var basePath = self.queryGeneratorGeo.getNavigationPath();
  352. //var path = basePath.concat(relativePath);
  353. var widget = payload;
  354. var queryGeneratorGeoTmp = self.queryGeneratorGeo.navigateToPath(path);
  355. var queryGeneratorGeo = queryGeneratorGeoTmp.copyExcludeConstraint(path);
  356. var task = self.fetchGeoms(queryGeneratorGeo, self.viewState.bounds);
  357. $.when(task).then(function(geomIndex) {
  358. var uriStrs = geomIndex.visibleGeoms;
  359. var uris = _.map(uriStrs, function(str) { return sparql.Node.uri(str); });
  360. console.log("GeomUris", uris);
  361. // alert("uris are:" + uris.length);
  362. var queryGenerator = queryGeneratorGeo.forGeoms(uris);
  363. var executor = new widgets.QueryExecutor(self.sparqlService, queryGenerator);
  364. widget = payload.getFacetValues();
  365. //console.log("Widget is", widget);
  366. //var viewModel = new widgets.ListModelExecutor(executor, 50);
  367. widget.setLabelFetcher(self.labelFetcher);
  368. widget.getModel().limit = 10;
  369. widget.getModel().setExecutor(executor);
  370. //widget.setModel(viewModel);
  371. // Note: Binding of the clickConstraint event is done in the facetbox widget
  372. /*
  373. widget.getView().getListWidget().bind("selected", function(ev, item) {
  374. / *
  375. console.log("item", item);
  376. var parent = item.item.getParent();
  377. var path = parent.model.get("path");
  378. console.log("path", path);* /
  379. //var path = item.item.model.get("path");
  380. //alert("boo");
  381. //console.log("boo", path);
  382. });*/
  383. //widget.setModel(executorModel);
  384. widget.refresh();
  385. });
  386. });
  387. this.facetBox.bind("clickConstraint", function(ev, payload) {
  388. var path = payload.path;
  389. //console.log("payload", payload.item);
  390. var item = payload.item;
  391. var facetValue = item.model.get("data").data;
  392. //console.log("facetValue", facetValue);
  393. var constraints = self.queryGeneratorGeo.getConstraints();
  394. //var constraints = self.constraints;
  395. console.log("path is", path);
  396. var constraint =
  397. new facets.PathConstraint(path,
  398. new facets.ConstraintEquals(new sparql.NodeValue(facetValue)));
  399. var id = "" + constraint;
  400. var model = new ns.ConstraintModel({id: id, value: constraint});
  401. //console.log("Setting constraint", constraint);
  402. //var isEnabled = !this.model.get("isEnabled");
  403. // console.log("Enabled:", isEnabled, id);
  404. if (item.isSelected()) {
  405. //alert("boo");
  406. //constraints.add(constraint);
  407. self.constraints.add(model);
  408. } else {
  409. self.constraints.remove(id);
  410. //constraints.remove(constraint);
  411. }
  412. //alert("Constraints", self.constraints);
  413. });
  414. this.facetBox.bind("pivot", function(ev, payload) {
  415. //console.log(payload.model.get("data"));
  416. var path = payload.model.get("data").path;
  417. var currentPath = self.executor.getNavigationPath();
  418. //this.queryGeneratorGeo.setNavigationPath(path);
  419. if(!currentPath) {
  420. currentPath = new facets.Path();
  421. }
  422. var concat = currentPath.concat(path);
  423. //alert("" + path);
  424. self.setNavigationPath(concat);
  425. //alert("Pivot");
  426. });
  427. //facetbox.createFacetBox();
  428. //this.facetbox = facetbox.createFacetBox(this.facetConfig, queryGenerator, basePath, facetBoxBackend, callbacks);
  429. //$('#tabs a:eq(3)').tab('show');
  430. $$.document.append(this.facetBox, "#tabs-content-facets");
  431. // $('#tabs a:first').tab('show');
  432. // TODO [HACK] Not sure why we need this hack of switching tabs
  433. // But without it, the facets do not show from the start; only after switching the incoming/outgoing tabs
  434. this.facetBox.view.$('a:eq(1)').tab('show');
  435. this.facetBox.view.$('a:first').tab('show');
  436. //$(window).resize();
  437. //this.constraintWidget = facetbox.createConstraintList(this.constraintSelections); //constraints);
  438. /*
  439. var ListModelBackbone = function(backboneCollection) {
  440. this.backboneCollection = backboneCollection;
  441. };
  442. ListModelBackbone.prototype.fetchData = function() {
  443. return this.backboneCollection;
  444. };
  445. */
  446. var ListModelConstraints = function(constraints) {
  447. this.constraints = constraints;
  448. };
  449. ListModelConstraints.prototype.fetchData = function() {
  450. var result = _.map(constraints.idToConstraints.entries, function(constraints, id) {
  451. var tmp = {data: constraints, id: id, label: id};
  452. console.log("Constraint Entry", tmp);
  453. return tmp;
  454. });
  455. return result;
  456. };
  457. var ItemViewConstraint = widgets.ItemViewLabel.extend({
  458. events: {
  459. 'click span': function(ev, payload) {
  460. var id = this.model.get("id");
  461. self.constraints.remove(id);
  462. }
  463. }
  464. });
  465. var constraintItemRenderer = new widgets.RendererItemView(this.constraintSelections, null, ItemViewConstraint, {
  466. label: "simpleLabel"
  467. /*
  468. label: function(model) {
  469. //console.log("AOEU", model); return "" + model.id;
  470. constraint = model.get("value");
  471. var result = constraintTextBuilder.fetchSimpleText(constraint);
  472. return result;
  473. }*/
  474. });
  475. this.constraintWidget = new widgets.ListView({
  476. el: $("#ssb-constraints"),
  477. collection: this.constraints,
  478. itemRenderer: constraintItemRenderer
  479. });
  480. /*
  481. $(this.constraintWidget).bind("click", function(ev, payload) {
  482. var id = payload.model.get("id");
  483. self.constraints.remove(id);
  484. //self.constraintSelections.remove(id);
  485. //payload.model.destroy();
  486. //console.log("moooo", payload);
  487. //alert("got it" + JSON.stringify(payload));
  488. });
  489. */
  490. //$$.document.append(self.constraintWidget, $("#ssb-constraints"));
  491. // React to changes of the constraints
  492. /*
  493. $(constraints).bind("change", function(ev, data) {
  494. self.repaint();
  495. console.log("change-event", data);
  496. _.each(data.added, function(entry) {
  497. self.constraintWidget.controller.addItem(entry.key, entry.value);
  498. $(window).resize();
  499. });
  500. _.each(data.removed, function(entry) {
  501. self.constraintWidget.controller.removeItem(entry);
  502. $(window).resize();
  503. });
  504. });
  505. */
  506. // Do layout
  507. $(window).resize();
  508. this.loadStartTab();
  509. };
  510. /**
  511. * The start tab contains elements for selecting a starting point for
  512. * filtering and navigation.
  513. *
  514. * There are different starting points:
  515. * - Everything
  516. * Initially, all resources are selected.
  517. * - Class
  518. * The instances of a class serve as starting points for navigation
  519. * - Geo
  520. * Geo resources are selected by default
  521. *
  522. * For each selection there is a small controller that configures the app accordingly:
  523. * If geo is chosen, special logic is required to create the polygon view:
  524. * - A lat/long constraint is set as the geo-constraint factory
  525. * - A projection path "isMemberOfWay georss" is declared
  526. * - The projection path is bound to the WKT-source of the view
  527. *
  528. *
  529. *
  530. * Note that in general the app distinguishes between selection and projection/view binding.
  531. *
  532. *
  533. */
  534. ns.AppController.prototype.updateGraphs = function() {
  535. console.log("data is", this.graphSelectionModel);
  536. var nodes = _.map(this.graphSelectionModel, function(item) {
  537. // Pitfall: Attaching jQuery events to an object adds new keys
  538. // So if we do it that way, our code must be able to deal with it.
  539. return item && item.data ? item.data.data : null;
  540. });
  541. var uris = _.filter(nodes, function(node) { return sparql.Node.isUri(node); });
  542. var defaultGraphs = _.map(uris, function(uri) { return uri.value; });
  543. // Flush the caches
  544. // FIXME Add support for caching when graphs (or other state properties) change
  545. this.hashToCache = {};
  546. console.log("New defaultGraphs", defaultGraphs);
  547. this.sparqlService.setDefaultGraphs(defaultGraphs);
  548. this.repaint();
  549. };
  550. ns.AppController.prototype.updateStartingPoint = function() {
  551. // The twist here is, that the label of the starting point depends on the selected language.
  552. };
  553. ns.AppController.prototype.loadStartTab = function() {
  554. this.classSelectionModel = {};
  555. this.graphSelectionModel = {};
  556. var self = this;
  557. var isWriteEnabled = config.isWriteEnabled;
  558. $(this.graphSelectionModel).bind("change", function() {
  559. //alert("test");
  560. console.log("self.graphSelectionModel", self.graphSelectionModel);
  561. self.updateGraphs();
  562. // TODO Hack set the write graph if there is only only graph selected
  563. // TODO Hack the graph selection should be sent to the event bus, and the RDFauthor adapter should listen.
  564. var selected = null;
  565. $.each(self.graphSelectionModel, function(key, value) {
  566. if(value.isSelected) {
  567. //console.log("The selected value is", value);
  568. if(!selected) {
  569. selected = value.data.data.value;
  570. } else {
  571. selected = null;
  572. return false;
  573. }
  574. }
  575. });
  576. if(isWriteEnabled) {
  577. config.targetGraph = null;
  578. if(selected) {
  579. alert("Writes will go to graph: " + selected);
  580. } else {
  581. //alert("Writes disabled because there is no longer a selected graph");
  582. }
  583. if(selected) {
  584. RDFAUTHOR_DEFAULT_GRAPH=selected;
  585. config.targetGraph = selected;
  586. //console.log("Checking:", $('link[rel="update:sourceGraph"]'));
  587. /*
  588. $('link[rel="update:queryEndpoint"]').attr({about: selected});
  589. $('link[rel="update:updateEndpoint"]').attr({about: selected});
  590. $('link[rel="update:sourceGraph"]').attr({about: selected, href: selected});
  591. $('link[rel="update:defaultGraph"]').attr({about: selected, href: selected});
  592. */
  593. }
  594. }
  595. });
  596. {
  597. var conceptVar = sparql.Node.v("c");
  598. //var conceptElement = queryUtils.createElementGetNamedGraphsFallback(conceptVar);
  599. var conceptElement = queryUtils.createElementGetNamedGraphs(conceptVar);
  600. var concept = new facets.ConceptInt(conceptElement, conceptVar);
  601. var queryGenerator = new widgets.QueryGenerator(concept);
  602. var executor = new widgets.QueryExecutor(this.sparqlService, queryGenerator);
  603. var viewModel = new widgets.ListModelExecutor(executor, 50);
  604. var renderer = new widgets.RendererCheckItem(this.graphSelectionModel, function(data) { return "" + data.data; });
  605. var executorWidget = new widgets.ExecutorListWidget(viewModel, renderer, this.labelFetcher);
  606. /*
  607. executorWidget.getView().getListWidget().bind("selected", function(ev, payload) {
  608. /*
  609. var data = payload.item.model.get("data").data;
  610. if(payload.checked) {
  611. self.graphSelectionModel[data] = {data: data, isSelected: true};
  612. } else {
  613. delete self.graphSelectionModel[data];
  614. }
  615. $(self.graphSelectionModel).trigger("change", self.graphSelectionModel);
  616. * /
  617. // FIXME This is hacky: We should depend on a model/collection event - not on a view one.
  618. })*/;
  619. $$.document.append(executorWidget.getView(), $("#ssb-graph-selection"));
  620. //executorWidget.getView().getListWidget().refresh();
  621. executorWidget.refresh();
  622. }
  623. {
  624. var conceptVar = sparql.Node.v("c");
  625. var conceptElement = queryUtils.createElementGetClasses(conceptVar);
  626. var concept = new facets.ConceptInt(conceptElement, conceptVar);
  627. var queryGenerator = new widgets.QueryGenerator(concept);
  628. var executor = new widgets.QueryExecutor(this.sparqlService, queryGenerator);
  629. var viewModel = new widgets.ListModelExecutor(executor, 50);
  630. var renderer = new widgets.RendererCheckItem(this.classSelectionModel, function(data) { return "" + data.data; });
  631. var executorWidget = new widgets.ExecutorListWidget(viewModel, renderer, this.labelFetcher);
  632. executorWidget.getView().getListWidget().bind("selected", function(ev, payload) {
  633. var data = payload.item.model.get("data").data;
  634. if(payload.checked) {
  635. self.classSelectionModel[data] = {data: data, isSelected: true};
  636. } else {
  637. delete self.classSelectionModel[data];
  638. }
  639. console.log("classSelection:" , self.classSelectionModel);
  640. });
  641. $$.document.append(executorWidget.getView(), $("#ssb-class-selection"));
  642. //executorWidget.getView().getListWidget().refresh();
  643. executorWidget.refresh();
  644. }
  645. // Resource search
  646. {
  647. var conceptVar = sparql.Node.v("c");
  648. var conceptElement = queryUtils.createElementAnyResource(conceptVar);
  649. var concept = new facets.ConceptInt(conceptElement, conceptVar);
  650. var queryGenerator = new widgets.QueryGenerator(concept);
  651. var executor = new widgets.QueryExecutor(this.sparqlService, queryGenerator);
  652. var viewModel = new widgets.ListModelExecutor(executor, 10);
  653. var renderer = new widgets.RendererString(function(data) { return "" + data.data.value; }, {label: function(data) { return "" + data.label; }});
  654. var executorWidget = new widgets.ExecutorListWidget(viewModel, renderer, this.labelFetcher);
  655. executorWidget.getView().getListWidget().bind("click", function(ev, payload) {
  656. var node = payload.data.data;
  657. self.showDescription([node]);
  658. $("#box-facts").show();
  659. //console.log("payload", payload);
  660. /*
  661. alert("yay");
  662. var data = payload.item.model.get("data").data;
  663. if(payload.checked) {
  664. self.classSelectionModel[data] = {data: data, isSelected: true};
  665. } else {
  666. delete self.classSelectionModel[data];
  667. }
  668. console.log("classSelection:" , self.classSelectionModel);
  669. */
  670. });
  671. $$.document.append(executorWidget.getView(), $("#ssb-resource-search"));
  672. //executorWidget.getView().getListWidget().refresh();
  673. executorWidget.refresh();
  674. }
  675. /*
  676. setTimeout(function() {
  677. this.doLayout();
  678. }, 1000);
  679. */
  680. /*
  681. {
  682. var conceptVar = sparql.Node.v("c");
  683. var conceptElement = queryUtils.createElementGetClasses(conceptVar);
  684. var concept = new facets.ConceptInt(conceptElement, conceptVar);
  685. var queryGenerator = new widgets.QueryGenerator(concept);
  686. var model = widgets.createListModelLabels(this.sparqlService, queryGenerator, {distinct: true}, this.labelFetcher);
  687. var listWidget = widgets.createListWidget(model, widgets.checkItemFactory);
  688. listWidget.sort();
  689. listWidget.bind("click", function(ev, payload) {
  690. alert(payload.checked + " " + payload.item.model.get("label"));
  691. });
  692. $$.document.append(listWidget, $("#ssb-class-selection"));
  693. }
  694. */
  695. /*
  696. console.log("PaginatorX", widgets.Paginator);
  697. var paginator = widgets.createPaginator();//$$(widgets.Paginator); //widgets.createPaginatorWidget(5);
  698. paginator.setMaxSlotCount(5);
  699. paginator.setPageCount(10);
  700. paginator.setCurrentPage(5);
  701. paginator.refresh();
  702. paginator.bind("click", function(ev, payload) {
  703. alert("click" + payload.getTargetPage());
  704. });
  705. //paginatorWidget.trimToSize(0);
  706. $$.document.append(paginator, $("#ssb-class-selection"));
  707. */
  708. //var sparqlListWidget = $$(widgets.ListWidgetSparql);
  709. /*
  710. var sparqlListWidget = widgets.createListWidgetSparql();
  711. $$.document.append(sparqlListWidget, $("#ssb-class-selection"));
  712. sparqlListWidget.refresh();
  713. */
  714. //var conceptElement = queryUtils.createElementGetNamedGraphsFallback(conceptVar);
  715. };
  716. ns.AppController.prototype.setNavigationPath = function(path) {
  717. //console.log("NavigationPath", path);
  718. //var concat = this.queryGenerator.navigationBreadcrumb.concat(breadcrumb);
  719. var concat = path;
  720. this.queryGeneratorGeo.setNavigationPath(path);
  721. //this.queryGenerator.navigationBreadcrumb = concat;
  722. //this.facetState = new facetbox.FacetState(this.facetConfig, this.queryGenerator.getInferredDriver(), concat);
  723. //this.facetState = new facetbox.FacetState(this.facetConfig, this.queryGenerator.concept, concat);
  724. //this.facetbox.controller.setState(this.facetState);
  725. //this.facebox.controller.setState(queryGenerator);
  726. // TODO - Set the FacetSate
  727. //console.log("TODO - Set the FacetSate");
  728. //this.facetbox.controller.refresh();
  729. //this.updateFacetsRec(this.executor, this.facetBox);
  730. this.updateFacets();
  731. var uris = _.map(path.getSteps(), function(step) {
  732. return step.propertyName;
  733. });
  734. var self = this;
  735. this.labelFetcher.fetch(uris).pipe(function(data) {
  736. self.breadcrumbWidget.controller.setPath(path, data.uriToLabel);
  737. self.repaint();
  738. });
  739. };
  740. ns.AppController.prototype.centerOnResource = function(node) {
  741. };
  742. // ns.AppController.prototype.showDescriptionOld = function(nodes) {
  743. // this.factBox.controller.setNodes(nodes);
  744. // };
  745. ns.AppController.prototype.initEvents = function() {
  746. var self = this;
  747. /*
  748. $("#facets").bind("ssb_facetschanged", function(event, ui) {
  749. //var sel = $("#facets").data;
  750. //console.log("Selection is:");
  751. //console.log(self.selection);
  752. //self.queryFactory.setClassFilter(self.selection);
  753. self.mapEvent();
  754. });*/
  755. $("#instances").bind("ssb_instancesclick", function(event, ui) {
  756. self.onInstanceClicked(ui.key);
  757. });
  758. $("#instances").bind("ssb_instanceshover", function(event, ui) {
  759. self.onInstanceHover(ui.key);
  760. });
  761. $("#instances").bind("ssb_instancesunhover", function(event, ui) {
  762. self.onInstanceUnhover(ui.key);
  763. });
  764. $("#map").bind("ssb_maponmarkerclick", function(event, ui) {
  765. self.onInstanceClicked(ui.nodeId);
  766. });
  767. $("#map").bind("ssb_maponmapevent", function(event, ui) {
  768. self.repaint();
  769. // Bind the map-event to the updateXXXXX
  770. // If everytihng is done, fire an event updateView
  771. // Refresh the view whenever it is sent
  772. });
  773. Dispatcher.register("selection", null, function(ev, uri) {
  774. // Fetch
  775. });
  776. Dispatcher.register("selection", null, function(ev, uri) {
  777. // TODO FFS Why did I use select rather than construct here?
  778. $.when(queryUtils.fetchStatementsBySubjects(self.sparqlService, [uri]))
  779. .then(function(jsonRdf) {
  780. // If there are any same as links, try to fetch something from
  781. // additional sources (e.g. DBpedia)
  782. //console.log(jsonRdf);
  783. //var objects = JsonRdfExtractionUtils.extractObjects(jsonRdf, uri, "http://www.w3.org/2002/07/owl#sameAs");
  784. var tags = extractTags(jsonRdf);
  785. objects = "owl:sameAs" in tags ? tags["owl:sameAs"] : [];
  786. for(prefix in self.prefixToService) {
  787. var service = self.prefixToService[prefix];
  788. for(var i = 0; i < objects.length; ++i) {
  789. var object = objects[i]; //.value;
  790. if(object.startsWith(prefix)) {
  791. fetchStatementsBySubject(service, [object], function(jsonRdf2) {
  792. //self.facts.setData(uri, [jsonRdf, jsonRdf2]);
  793. });
  794. }
  795. }
  796. }
  797. });
  798. });
  799. };
  800. /**
  801. * Flushes the given resources from all caches that are known by the controller.
  802. * Specifically:
  803. * - label cache
  804. * - geometry cache
  805. * - quad tree cache (nodes containing flush resources are reset to "not loaded")
  806. *
  807. */
  808. ns.AppController.flushCacheResources = function(nodes) {
  809. // TODO Implement me
  810. };
  811. /**
  812. * Fetch geometries within the given bounds
  813. *
  814. * @param queryGeneratorGeo
  815. * @param bounds
  816. * @returns
  817. */
  818. ns.AppController.prototype.fetchGeoms = function(queryGeneratorGeo, bounds) {
  819. var task = this.fetchNodesGeo(queryGeneratorGeo, bounds);
  820. var result = $.Deferred();
  821. var self = this;
  822. $.when(task).then(function(nodes) {
  823. var geomIndex = ns.indexGeoms(nodes, bounds);
  824. var tmp = {
  825. bounds: bounds,
  826. nodes: nodes,
  827. visibleGeoms: geomIndex.visibleGeoms,
  828. geomToPoint: geomIndex.geomToPoint};
  829. result.resolve(tmp);
  830. }).fail(function() {
  831. result.fail();
  832. });
  833. return result.promise();
  834. };
  835. /**
  836. * TODO Factor out into a separate object
  837. *
  838. */
  839. ns.AppController.prototype.fetchNodesGeo = function(queryGeneratorGeo, bounds) {
  840. //console.log("Refresh bounds", bounds);
  841. // TODO Check if another refresh request is running.
  842. // If so, make this request wait for the other running one, thereby
  843. // replacing any other already pending request
  844. var disableConstraints = true;
  845. //-- console.log("Constraints", queryGeneratorGeo.getConstraints());
  846. var queryGenerator = queryGeneratorGeo.forGlobal({disableConstraints: disableConstraints});
  847. //-- console.log("The queryGenerator is: ", queryGeneratorGeo);
  848. var baseElement = queryGenerator.createDriverValues().getElement();
  849. //var baseElement = this.queryGenerator.forGlobal(); //elementFactoryGeo.concept.element;
  850. var hash = baseElement.toString();
  851. //-- console.log("Query hash (including facets): ", hash);
  852. var cacheEntry = this.hashToCache[hash];
  853. if(!cacheEntry) {
  854. var backendFactory = new qtc.BackendFactory(this.sparqlService, queryGeneratorGeo);
  855. cacheEntry = new qtc.QuadTreeCache(backendFactory, this.labelFetcher, this.geomPointFetcher, this.options.config.quadTree);
  856. //cacheEntry = new qt.QuadTree(maxBounds, 18, 0);
  857. this.hashToCache[hash] = cacheEntry;
  858. }
  859. var result = cacheEntry.load(bounds);
  860. return result;
  861. };
  862. /**
  863. * Given bounds and a set of quat tree nodes, this method
  864. * Creates a map resource->geometry and also determines which resources are visible
  865. */
  866. ns.indexGeoms = function(nodes, bounds) {
  867. if(!nodes) {
  868. // FIXME undefined 'nodes' happens, if there was an empty set of geometries or
  869. // a query failed. this should be trapped at a different location than here
  870. console.log("No nodes to index, should not happen; using workaround");
  871. nodes = [];
  872. }
  873. var globalGeomToPoint = {};
  874. var visibleGeoms = [];
  875. for(var i = 0; i < nodes.length; ++i) {
  876. var node = nodes[i];
  877. var nodeBounds = node.getBounds();
  878. var databank = node.data.graph;
  879. var geomToPoint = node.data.geomToPoint ? node.data.geomToPoint : ns.extractGeomsWgs84(databank);
  880. //console.debug("geomToPoint", geomToPoint);
  881. //console.debug("Databank for node ", i, databank);
  882. // Attach the info to the node, so we reuse it the next time
  883. node.data.geomToPoint = geomToPoint;
  884. _.extend(globalGeomToPoint, geomToPoint);
  885. var geoms = _.keys(geomToPoint);
  886. // If the node is completely in the bounds, we can skip the boundary check
  887. if(bounds.contains(nodeBounds)) {
  888. visibleGeoms.push.apply(visibleGeoms, geoms);
  889. } else if(bounds.isOverlap(nodeBounds)) {
  890. //for(var geom in geoms) {
  891. for(var j = 0; j < geoms.length; ++j) {
  892. var geom = geoms[j];
  893. var point = geomToPoint[geom];
  894. //console.log("point is: ", geomToPoint);
  895. if(bounds.containsPoint(point)) {
  896. visibleGeoms.push(geom);
  897. }
  898. }
  899. }
  900. }
  901. return {geomToPoint: globalGeomToPoint, visibleGeoms: visibleGeoms};
  902. };
  903. ns.AppController.prototype.refresh = function(olBounds) {
  904. var self = this;
  905. // We are dealing with quad-tree-bounds here
  906. var bounds = toQuadTreeBounds(olBounds);
  907. //console.log("Refresh bounds", bounds);
  908. var promise = this.fetchNodesGeo(this.queryGeneratorGeo, bounds);
  909. promise.done(function(nodes) {
  910. // TODO Properly check if an old request is running
  911. // and schedule the next request
  912. if(!nodes) {
  913. console.log("Skipping refresh because an update is in progress");
  914. return;
  915. }
  916. //console.debug("Loaded " + nodes.length + " nodes");
  917. //console.debug("Nodes are:", nodes);
  918. self.updateViews(new ns.ViewState(nodes, bounds));
  919. });
  920. };
  921. ns.AppController.prototype.repaint = function() {
  922. var map = this.map;
  923. var bounds = map.getExtent().transform(map.projection, map.displayProjection);
  924. /*
  925. var minZoom = 15;
  926. if(zoom < minZoom) {
  927. self.notificationScheduler.schedule(function() { notify("Info", "Disabled fetching data because current zoom level " + zoom + " is less than the minimum " + minZoom + ".");});
  928. return;
  929. }*/
  930. this.refresh(bounds, true);
  931. };
  932. ns.AppController.prototype.addFactSources = function(prefixToService) {
  933. var self = this;
  934. for(key in prefixToService) {
  935. self.prefixToService[key] = prefixToService[key];
  936. }
  937. };
  938. ns.AppController.prototype.setQueryFactory = function(queryFactory) {
  939. this.queryFactory = queryFactory;
  940. };
  941. ns.AppController.prototype.setFacetConfig = function(facetConfig) {
  942. this.facetConfig = facetConfig;
  943. };
  944. ns.AppController.extract = function(jsonRdf) {
  945. //for(var i = 0; i < jsonRdfs.result.bindings)
  946. };
  947. /*
  948. ns.createMap = function(databank, pattern, keyVar, valVar) {
  949. var result = {};
  950. rdf.where("?" + keyVar + " " + geo.long + " ?" + valVar).each(function() {
  951. result[this[keyVar] = this..value;
  952. });
  953. };*/
  954. /**
  955. * Indexes geometries in the given datastore
  956. *
  957. * NOTE Assumes that geometries only have a single lon/lat pair.
  958. * If there are multiple ones, an arbitrary pair is chosen.
  959. * If there is a lat but no long, or vice versa, the resource does not appear in the output
  960. *
  961. * @returns
  962. */
  963. ns.extractGeomsWgs84 = function(databank) {
  964. var rdf = $.rdf({databank: databank});
  965. var result = {};
  966. var geomToX = {};
  967. var geomToY = {};
  968. rdf.where("?geom " + geo.lon + " ?x .").each(function() {
  969. geomToX[this.geom.value] = this.x.value;
  970. });
  971. rdf.where("?geom " + geo.lat + " ?y").each(function() {
  972. geomToY[this.geom.value] = this.y.value;
  973. });
  974. for(var geom in geomToX) {
  975. if(geom in geomToY) {
  976. var point = new qt.Point(geomToX[geom], geomToY[geom]);
  977. result[geom] = point;
  978. }
  979. }
  980. return result;
  981. };
  982. /**
  983. * OPTIMIZE Actually we could cache the counts for nodes that are
  984. * completely contained in the visible area and thereby
  985. * avoid further queries.
  986. *
  987. * @param bounds
  988. * @param nodes
  989. *
  990. */
  991. /*
  992. ns.AppController.prototype.updateFacetCounts = function(bounds, nodes) {
  993. var query = this.createFacetQueryCountVisible(bounds, nodes);
  994. //console.log("Facet Query - Visible", this.viewState.visibleGeoms.length);
  995. //console.log("Facet Query", query);
  996. this.sparqlService.executeSelect(query.toString(), {
  997. success: function() {
  998. //alert("Wee");
  999. }
  1000. });
  1001. };
  1002. */
  1003. /**
  1004. * Create the model for the facet box
  1005. *
  1006. */
  1007. ns.postProcessFacets = function(facets, pivotFacets, labelFetcher) {
  1008. // Index pivot facets
  1009. var pivotStrs = {};
  1010. _.each(pivotFacets.facets, function(item) {
  1011. if(item.isUri()) {
  1012. pivotStrs[item.value] = true;
  1013. }
  1014. });
  1015. // Check pivot state
  1016. //var collection = [];
  1017. _.each(facets, function(item) {
  1018. // Note: Facets must all be URIs, but better check
  1019. var isPivotable = true;
  1020. //var isPivotable = false;
  1021. if(item.node.isUri()) {
  1022. var str = item.node.value;
  1023. if(str in pivotStrs) {
  1024. isPivotable = true;
  1025. }
  1026. }
  1027. item.countStr = "" + item.count;
  1028. item.isPivotable = isPivotable;
  1029. });
  1030. // Fetch labels
  1031. var uriStrs = [];
  1032. _.each(facets, function(item) {
  1033. if(item.node.isUri()) {
  1034. uriStrs.push(item.node.value);
  1035. }
  1036. });
  1037. var promise = labelFetcher.fetch(uriStrs).pipe(function(labels) {
  1038. _.each(facets, function(item) {
  1039. var label = labels.uriToLabel[item.node.value];
  1040. item.label = label ? label.value : "" + item.node;
  1041. });
  1042. return facets;
  1043. });
  1044. return promise;
  1045. };
  1046. ns.AppController.prototype.updateFacetsRecDir = function(executor, view, isInverse, path) {
  1047. var self = this;
  1048. //var pivotFacets = executor.fetchPivotFacets();
  1049. var pivotFacetsTask = $.Deferred();
  1050. pivotFacetsTask.resolve({});
  1051. var facetCountTask = executor.fetchCountDistinctFacets(isInverse);
  1052. // Fetches the count of distinct objects per property
  1053. //$.when(executor.fetchValuesCounted(), pivotFacetsTask).then(function(facetCollection, pivotFacets) {
  1054. $.when(facetCountTask, pivotFacetsTask).then(function(facetCollection, pivotFacets) {
  1055. //console.log("FacetCollection: ", facetCollection);
  1056. var promise = ns.postProcessFacets(facetCollection, pivotFacets, self.labelFetcher);
  1057. $.when(promise).then(function(facetCollection) {
  1058. _.each(facetCollection, function(item) {
  1059. var propertyName = item.node.value;
  1060. var step = new facets.Step(propertyName, isInverse);
  1061. item.path = path.copyAppendStep(step);
  1062. });
  1063. //console.log("FacetSatus", facetCollection);
  1064. //view.setCollection(facetCollection);
  1065. view.getModel().setData(facetCollection);
  1066. view.refresh();
  1067. });
  1068. });
  1069. };
  1070. ns.AppController.prototype.updateFacetsRec = function(executor, view) {
  1071. var path = new facets.Path(); //executor.getNavigationPath();
  1072. this.updateFacetsRecDir(executor, view.getOutgoing(), false, path);
  1073. this.updateFacetsRecDir(executor, view.getIncoming(), true, path);
  1074. /*
  1075. executorIncoming = executor.navigateToFacets(-1);
  1076. executorOutgoing = executor.navigateToFacets(1);
  1077. this.updateFacetsRecDir(executorOutgoing, view.getOutgoing(), false, path);
  1078. this.updateFacetsRecDir(executorIncoming, view.getIncoming(), true, path);
  1079. */
  1080. };
  1081. ns.AppController.prototype.updateFacets = function() {
  1082. if(!this.executor) {
  1083. console.log("No executor set (yet)");
  1084. return;
  1085. }
  1086. this.updateFacetsRec(this.executor, this.facetBox);
  1087. };
  1088. /**
  1089. * Updates the facet counts considering all constraints.
  1090. * This deviates from the usual facet behaviour:
  1091. * Usally the count of a specific facet is based on an exclusion of all of its constraints.
  1092. *
  1093. * @param uris
  1094. */
  1095. ns.AppController.prototype.updateFacetCountsGeom = function(uris) {
  1096. if(uris.length === 0) {
  1097. this.facetBox.getIncoming().getModel().setData([]);
  1098. this.facetBox.getOutgoing().getModel().setData([]);
  1099. this.facetBox.getIncoming().refresh();
  1100. this.facetBox.getOutgoing().refresh();
  1101. return;
  1102. }
  1103. var queryGenerator = this.queryGeneratorGeo.forGeoms(uris);
  1104. this.executor = new widgets.QueryExecutor(this.sparqlService, queryGenerator);
  1105. this.updateFacets();
  1106. /*
  1107. executor.fetchValues().pipe(function(data) {
  1108. alert(data);
  1109. });
  1110. */
  1111. //var generator = widgets.QueryGenerator(concept, );
  1112. if(true) {
  1113. //console.warn("Facets disabled", uris);
  1114. return;
  1115. }
  1116. // TODO Remove below
  1117. /*
  1118. var self = this;
  1119. var concept = queryUtils.createFacetQueryCountVisibleGeomNested(this.queryGenerator, uris);
  1120. // Set the concept of the facet state to the new query element
  1121. //this.facetState.concept = concept;
  1122. //console.log("Facet Query - Visible", this.viewState.visibleGeoms.length);
  1123. //console.log("Facet Query", concept);
  1124. // clear the pathManager
  1125. //var propertyToNode = this.facetState.pathManager.getRoot().outgoing;
  1126. //this.facetState.clearCounts();
  1127. if(!uris.length) {
  1128. //self.facetbox.controller.setState(null);
  1129. self.facetbox.controller.refresh();
  1130. return;
  1131. }
  1132. var state = this.facetState;
  1133. //var node = state.pathManager.getRoot();
  1134. //this.queryGenerator.getNavigationTarget();
  1135. var node = this.queryGenerator.navigationBreadcrumb.targetNode;
  1136. //var breadcrumbs = this.facetbox.controller.getVisibleBreadcrumbsValues();
  1137. // TODO: The method should return a pure json object such as an array holding information about the
  1138. // steps and sub-steps
  1139. // [ {step: foo, page: 2, facetValues: [baaaar], children: [ ] ]
  1140. var stepStrToItem = this.facetbox.controller.getVisiblePropertiesValues();
  1141. var self = this;
  1142. // Once all facet counts have been obtained, and the pivoting abilities have been checked, update the view
  1143. var facetCountTask = queryUtils.fetchFacetCountsGeomRec(this.sparqlService, this.labelFetcher, state, node, stepStrToItem);
  1144. var pivotCheckTask = queryUtils.fetchPivotFacets(this.sparqlService, state.concept);
  1145. $.when(facetCountTask, pivotCheckTask).then(function(facetState, pivotFacets) {
  1146. var steps = _.map(pivotFacets, function(item) { return new facets.Step(item.value); });
  1147. //alert("Pivoting enabled facets:" + pivotFacets);
  1148. //console.log("facetstate", facetState);
  1149. //self.facetbox.controller.setState(state);
  1150. self.facetbox.controller.refresh();
  1151. self.facetbox.controller.setPivotFacets(steps);
  1152. })
  1153. */
  1154. };
  1155. ns.AppController.getLoadedNodes = function(nodes) {
  1156. var result = [];
  1157. for(var i = 0; i < nodes.length; ++i) {
  1158. var node = nodes[i];
  1159. if(!node.data.tooManyItems || node.isLoaded) {
  1160. result.push(node);
  1161. }
  1162. }
  1163. return result;
  1164. };
  1165. ns.AppController.prototype.updateViews = function(newState) {
  1166. // TODO Somehow make this work (by magic is would be fine)
  1167. // TODO Facet counts are updated as a reaction to fetching the new state
  1168. //this.updateFacetCounts(newState.bounds, newState.nodes);
  1169. // node 1 2
  1170. // change
  1171. // instances (only applicable for partially visible nodes)
  1172. //console.log("Updating views");
  1173. var oldVisibleGeoms = this.viewState.visibleGeoms;
  1174. var nodes = newState.nodes;
  1175. var bounds = newState.bounds;
  1176. this.viewState = newState;
  1177. var nodeIndex = ns.indexGeoms(nodes, bounds);
  1178. var globalGeomToPoint = nodeIndex.geomToPoint;
  1179. var visibleGeoms = nodeIndex.visibleGeoms;
  1180. this.viewState.visibleGeoms = visibleGeoms;
  1181. /*
  1182. // Get all geometries from the databanks
  1183. for(var i = 0; i < nodes.length; ++i) {
  1184. var node = nodes[i];
  1185. var nodeBounds = node.getBounds();
  1186. var databank = node.data.graph;
  1187. var geomToPoint = node.data.geomToPoint ? node.data.geomToPoint : ns.extractGeomsWgs84(databank);
  1188. //console.debug("geomToPoint", geomToPoint);
  1189. //console.debug("Databank for node ", i, databank);
  1190. // Attach the info to the node, so we reuse it the next time
  1191. node.data.geomToPoint = geomToPoint;
  1192. _.extend(globalGeomToPoint, geomToPoint);
  1193. var geoms = _.keys(geomToPoint);
  1194. // If the node is completely in the bounds, we can skip the boundary check
  1195. if(bounds.contains(nodeBounds)) {
  1196. visibleGeoms.push.apply(visibleGeoms, geoms);
  1197. } else if(bounds.isOverlap(nodeBounds)) {
  1198. //for(var geom in geoms) {
  1199. for(var j = 0; j < geoms.length; ++j) {
  1200. var geom = geoms[j];
  1201. var point = geomToPoint[geom];
  1202. //console.log("point is: ", geomToPoint);
  1203. if(bounds.containsPoint(point)) {
  1204. visibleGeoms.push(geom);
  1205. }
  1206. }
  1207. }
  1208. }
  1209. */
  1210. //console.debug("Number of visible geoms", visibleGeoms.length);
  1211. // Combine the datastores
  1212. for(var i = 0; i < nodes.length; ++i) {
  1213. var node = nodes[i];
  1214. var databank = node.data.graph;
  1215. // TODO Rather adding the datastore directly
  1216. // invoke a method that activates the node in the cache
  1217. this.multiGraph.addDatabank(databank);
  1218. }
  1219. /*
  1220. * Load:
  1221. * 1) relations between geometries and features
  1222. * 2) labels of the features
  1223. */
  1224. var geomToFeatures = collections.BidiMultiMap.createWithSet();
  1225. var geomToFeatureCount = {};
  1226. var idToLabel = {}; // TODO I don't think there is much point in having the labels here already; they should be fetched separately using the LabelFetcher
  1227. for(var i = 0; i < nodes.length; ++i) {
  1228. var node = nodes[i];
  1229. if(!node.isLoaded) {
  1230. continue;
  1231. }
  1232. var databank = node.data.graph;
  1233. var rdf = $.rdf({databank: databank});
  1234. rdf.where("?id " + geovocab.geometry + " ?geom").each(function() {
  1235. //console.log("entry", this.geom, this.id);
  1236. geomToFeatures.put(this.geom.value, this.id.value);
  1237. });
  1238. rdf.where("?geom " + appvocab.featureCount + " ?featureCount").each(function() {
  1239. //geomToFeatureCount.put(this.geom.value, this.featureCount.value);
  1240. geomToFeatureCount[this.geom.value] = this.featureCount.value;
  1241. });
  1242. rdf.where("?id " + rdfs.label + " ?label").each(function() {
  1243. idToLabel[this.id.value] = this.label.value;
  1244. });
  1245. }
  1246. //console.debug("View refresh status", geomToFeatureCount, idToLabel);
  1247. //console.debug("Visible geoms", visibleGeoms);
  1248. //console.log("idToLabel", idToLabel);
  1249. // TODO Separate the following part into a new method
  1250. // (First part does the data fetching/preparation,
  1251. // second part applies it)
  1252. var addedGeoms = _.difference(visibleGeoms, oldVisibleGeoms);
  1253. var removedGeoms = _.difference(oldVisibleGeoms, visibleGeoms);
  1254. /*
  1255. * Updates of views below
  1256. *
  1257. */
  1258. var useOldMethod = false;
  1259. if(useOldMethod) {
  1260. this.mapWidget.removeItems(removedGeoms);
  1261. /*
  1262. for(var i = 0; i < removedGeoms.length; ++i) {
  1263. //var geom = removedGeoms[i];
  1264. }*/
  1265. for(var i = 0; i < addedGeoms.length; ++i) {
  1266. var geom = addedGeoms[i];
  1267. var point = globalGeomToPoint[geom];
  1268. var lonlat = new OpenLayers.LonLat(point.x, point.y);
  1269. //console.debug("Adding map item", geom, point, lonlat);
  1270. this.mapWidget.addItem(geom, lonlat, true);
  1271. }
  1272. }
  1273. var boxIds = _.keys(this.mapWidget.idToBox);
  1274. for(var i = 0; i < boxIds.length; ++i) {
  1275. var boxId = boxIds[i];
  1276. this.mapWidget.removeBox(boxId);