Synchro back-office, fix on tariffs
This commit is contained in:
18
build/js/site.js
Normal file
18
build/js/site.js
Normal file
@@ -0,0 +1,18 @@
|
||||
// Prevent closing from click inside dropdown
|
||||
$(document).on('click', '.dropdown-menu', function (e) {
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
// make it as accordion for smaller screens
|
||||
if ($(window).width() < 992) {
|
||||
$('.dropdown-menu a').click(function(e){
|
||||
e.preventDefault();
|
||||
if($(this).next('.submenu').length){
|
||||
$(this).next('.submenu').toggle();
|
||||
}
|
||||
$('.dropdown').on('hide.bs.dropdown', function () {
|
||||
$(this).find('.submenu').hide();
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
520
build/js/taxonomy-browser.js
Normal file
520
build/js/taxonomy-browser.js
Normal file
@@ -0,0 +1,520 @@
|
||||
/*!
|
||||
* Fancytree Taxonomy Browser
|
||||
*
|
||||
* Copyright (c) 2015, Martin Wendt (https://wwWendt.de)
|
||||
*
|
||||
* Released under the MIT license
|
||||
* https://github.com/mar10/fancytree/wiki/LicenseInfo
|
||||
*
|
||||
* @version @VERSION
|
||||
* @date @DATE
|
||||
*/
|
||||
|
||||
/* global Handlebars */
|
||||
/* eslint-disable no-console */
|
||||
|
||||
(function($, window, document) {
|
||||
"use strict";
|
||||
|
||||
/*******************************************************************************
|
||||
* Private functions and variables
|
||||
*/
|
||||
|
||||
var taxonTree,
|
||||
searchResultTree,
|
||||
tmplDetails,
|
||||
tmplInfoPane,
|
||||
tmplMedia,
|
||||
timerMap = {},
|
||||
USER_AGENT = "Fancytree Taxonomy Browser/1.0",
|
||||
GBIF_URL = "//api.gbif.org/v1/",
|
||||
TAXONOMY_KEY = "d7dddbf4-2cf0-4f39-9b2a-bb099caae36c", // GBIF backbone taxonomy
|
||||
SEARCH_PAGE_SIZE = 5,
|
||||
CHILD_NODE_PAGE_SIZE = 200,
|
||||
glyphOpts = {
|
||||
preset: "bootstrap3",
|
||||
map: {
|
||||
expanderClosed: "glyphicon glyphicon-menu-right", // glyphicon-plus-sign
|
||||
expanderLazy: "glyphicon glyphicon-menu-right", // glyphicon-plus-sign
|
||||
expanderOpen: "glyphicon glyphicon-menu-down", // glyphicon-collapse-down
|
||||
},
|
||||
};
|
||||
|
||||
// Load and compile handlebar templates
|
||||
|
||||
$.get("details.tmpl.html", function(data) {
|
||||
tmplDetails = Handlebars.compile(data);
|
||||
Handlebars.registerPartial("tmplDetails", tmplDetails);
|
||||
});
|
||||
$.get("media.tmpl.html", function(data) {
|
||||
tmplMedia = Handlebars.compile(data);
|
||||
Handlebars.registerPartial("tmplMedia", tmplMedia);
|
||||
});
|
||||
$.get("info-pane.tmpl.html", function(data) {
|
||||
tmplInfoPane = Handlebars.compile(data);
|
||||
});
|
||||
|
||||
/** Update UI elements according to current status
|
||||
*/
|
||||
function updateControls() {
|
||||
var query = $.trim($("input[name=query]").val());
|
||||
|
||||
$("#btnPin").attr("disabled", !taxonTree.getActiveNode());
|
||||
$("#btnUnpin")
|
||||
.attr("disabled", !taxonTree.isFilterActive())
|
||||
.toggleClass("btn-success", taxonTree.isFilterActive());
|
||||
$("#btnResetSearch").attr("disabled", query.length === 0);
|
||||
$("#btnSearch").attr("disabled", query.length < 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke callback after `ms` milliseconds.
|
||||
* Any pending action of this type is cancelled before.
|
||||
*/
|
||||
function _delay(tag, ms, callback) {
|
||||
/*jshint -W040:true */
|
||||
var self = this;
|
||||
|
||||
tag = "" + (tag || "default");
|
||||
if (timerMap[tag] != null) {
|
||||
clearTimeout(timerMap[tag]);
|
||||
delete timerMap[tag];
|
||||
// console.log("Cancel timer '" + tag + "'");
|
||||
}
|
||||
if (ms == null || callback == null) {
|
||||
return;
|
||||
}
|
||||
// console.log("Start timer '" + tag + "'");
|
||||
timerMap[tag] = setTimeout(function() {
|
||||
// console.log("Execute timer '" + tag + "'");
|
||||
callback.call(self);
|
||||
}, +ms);
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
function _callWebservice(cmd, data) {
|
||||
return $.ajax({
|
||||
url: GBIF_URL + cmd,
|
||||
data: $.extend({}, data),
|
||||
cache: true,
|
||||
headers: { "Api-User-Agent": USER_AGENT },
|
||||
dataType: "jsonp",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
function updateItemDetails(key) {
|
||||
$("#tmplDetails").addClass("busy");
|
||||
$.bbq.pushState({ key: key });
|
||||
|
||||
$.when(
|
||||
_callWebservice("species/" + key),
|
||||
_callWebservice("species/" + key + "/speciesProfiles"),
|
||||
_callWebservice("species/" + key + "/synonyms"),
|
||||
_callWebservice("species/" + key + "/descriptions"),
|
||||
_callWebservice("species/" + key + "/media")
|
||||
).done(function(species, profiles, synonyms, descriptions, media) {
|
||||
// Requests are resolved as: [ data, statusText, jqXHR ]
|
||||
species = species[0];
|
||||
profiles = profiles[0];
|
||||
synonyms = synonyms[0];
|
||||
descriptions = descriptions[0];
|
||||
media = media[0];
|
||||
|
||||
var info = $.extend(species, {
|
||||
profileList: profiles.results, // marine, extinct
|
||||
profile:
|
||||
profiles.results.length === 1 ? profiles.results[0] : null, // marine, extinct
|
||||
synonyms: synonyms.results,
|
||||
descriptions: descriptions.results,
|
||||
descriptionsByLang: {},
|
||||
media: media.results,
|
||||
now: new Date().toString(),
|
||||
});
|
||||
|
||||
$.each(info.descriptions, function(i, o) {
|
||||
if (!info.descriptionsByLang[o.language]) {
|
||||
info.descriptionsByLang[o.language] = [];
|
||||
}
|
||||
info.descriptionsByLang[o.language].push(o);
|
||||
});
|
||||
|
||||
console.log("updateItemDetails", info);
|
||||
$("#tmplDetails")
|
||||
// .html(tmplDetails(info))
|
||||
.removeClass("busy");
|
||||
$("#tmplMedia")
|
||||
// .html(tmplMedia(info))
|
||||
.removeClass("busy");
|
||||
$("#tmplInfoPane")
|
||||
.html(tmplInfoPane(info))
|
||||
.removeClass("busy");
|
||||
|
||||
$("[data-toggle='popover']").popover();
|
||||
$(".carousel").carousel();
|
||||
$("#mediaCounter").text("" + (media.results.length || ""));
|
||||
// $("[data-toggle='collapse']").collapse();
|
||||
updateControls();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
function updateBreadcrumb(key, loadTreeNodes) {
|
||||
var $ol = $("ol.breadcrumb").addClass("busy"),
|
||||
activeNode = taxonTree.getActiveNode();
|
||||
|
||||
if (activeNode && activeNode.key !== key) {
|
||||
activeNode.setActive(false); // deactivate, in case the new key is not found
|
||||
}
|
||||
$.when(
|
||||
_callWebservice("species/" + key + "/parents"),
|
||||
_callWebservice("species/" + key)
|
||||
).done(function(parents, node) {
|
||||
// Both requests resolved (result format: [ data, statusText, jqXHR ])
|
||||
var nodeList = parents[0],
|
||||
keyList = [];
|
||||
|
||||
nodeList.push(node[0]);
|
||||
|
||||
// Display as <OL> list (for Bootstrap breadcrumbs)
|
||||
$ol.empty().removeClass("busy");
|
||||
$.each(nodeList, function(i, o) {
|
||||
var name = o.vernacularName || o.canonicalName;
|
||||
keyList.push(o.key);
|
||||
if ("" + o.key === "" + key) {
|
||||
$ol.append(
|
||||
$("<li class='active'>").append(
|
||||
$("<span>", {
|
||||
text: name,
|
||||
title: o.rank,
|
||||
})
|
||||
)
|
||||
);
|
||||
} else {
|
||||
$ol.append(
|
||||
$("<li>").append(
|
||||
$("<a>", {
|
||||
href: "#key=" + o.key,
|
||||
text: name,
|
||||
title: o.rank,
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
if (loadTreeNodes) {
|
||||
// console.log("updateBreadcrumb - loadKeyPath", keyList);
|
||||
taxonTree.loadKeyPath("/" + keyList.join("/"), function(
|
||||
n,
|
||||
status
|
||||
) {
|
||||
// console.log("... updateBreadcrumb - loadKeyPath " + n.title + ": " + status);
|
||||
switch (status) {
|
||||
case "loaded":
|
||||
n.makeVisible();
|
||||
break;
|
||||
case "ok":
|
||||
n.setActive();
|
||||
// n.makeVisible();
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
function search(query) {
|
||||
query = $.trim(query);
|
||||
console.log("searching for '" + query + "'...");
|
||||
// Store the source options for optional paging
|
||||
searchResultTree.lastSourceOpts = {
|
||||
// url: GBIF_URL + "species/match", // Fuzzy matches scientific names against the GBIF Backbone Taxonomy
|
||||
url: GBIF_URL + "species/search", // Full text search of name usages covering the scientific and vernacular name, the species description, distribution and the entire classification across all name usages of all or some checklists
|
||||
data: {
|
||||
q: query,
|
||||
datasetKey: TAXONOMY_KEY,
|
||||
// name: query,
|
||||
// strict: "true",
|
||||
// hl: true,
|
||||
limit: SEARCH_PAGE_SIZE,
|
||||
offset: 0,
|
||||
},
|
||||
cache: true,
|
||||
// headers: { "Api-User-Agent": USER_AGENT }
|
||||
// dataType: "jsonp"
|
||||
};
|
||||
$("#searchResultTree").addClass("busy");
|
||||
searchResultTree
|
||||
.reload(searchResultTree.lastSourceOpts)
|
||||
.done(function(result) {
|
||||
// console.log("search returned", result);
|
||||
if (result.length < 1) {
|
||||
searchResultTree.getRootNode().setStatus("nodata");
|
||||
}
|
||||
$("#searchResultTree").removeClass("busy");
|
||||
|
||||
// https://github.com/tbasse/jquery-truncate
|
||||
// SLOW!
|
||||
// $("div.truncate").truncate({
|
||||
// multiline: true
|
||||
// });
|
||||
|
||||
updateControls();
|
||||
});
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Pageload Handler
|
||||
*/
|
||||
|
||||
$(function() {
|
||||
$("#taxonTree").fancytree({
|
||||
extensions: ["filter", "glyph", "wide"],
|
||||
filter: {
|
||||
mode: "hide",
|
||||
},
|
||||
glyph: glyphOpts,
|
||||
autoCollapse: true,
|
||||
activeVisible: true,
|
||||
autoScroll: true,
|
||||
source: {
|
||||
url: GBIF_URL + "species/root/" + TAXONOMY_KEY,
|
||||
data: {},
|
||||
cache: true,
|
||||
// dataType: "jsonp"
|
||||
},
|
||||
init: function(event, data) {
|
||||
updateControls();
|
||||
$(window).trigger("hashchange"); // trigger on initial page load
|
||||
},
|
||||
lazyLoad: function(event, data) {
|
||||
data.result = {
|
||||
url: GBIF_URL + "species/" + data.node.key + "/children",
|
||||
data: {
|
||||
limit: CHILD_NODE_PAGE_SIZE,
|
||||
},
|
||||
cache: true,
|
||||
// dataType: "jsonp"
|
||||
};
|
||||
// store this request options for later paging
|
||||
data.node.lastSourceOpts = data.result;
|
||||
},
|
||||
postProcess: function(event, data) {
|
||||
var response = data.response;
|
||||
|
||||
data.node.info("taxonTree postProcess", response);
|
||||
data.result = $.map(response.results, function(o) {
|
||||
return (
|
||||
o && {
|
||||
title: o.vernacularName || o.canonicalName,
|
||||
key: o.key,
|
||||
nubKey: o.nubKey,
|
||||
folder: true,
|
||||
lazy: true,
|
||||
}
|
||||
);
|
||||
});
|
||||
if (response.endOfRecords === false) {
|
||||
// Allow paging
|
||||
data.result.push({
|
||||
title: "(more)",
|
||||
statusNodeType: "paging",
|
||||
});
|
||||
} else {
|
||||
// No need to store the extra data
|
||||
delete data.node.lastSourceOpts;
|
||||
}
|
||||
},
|
||||
activate: function(event, data) {
|
||||
$("#tmplDetails").addClass("busy");
|
||||
$("ol.breadcrumb").addClass("busy");
|
||||
updateControls();
|
||||
_delay("showDetails", 500, function() {
|
||||
updateItemDetails(data.node.key);
|
||||
updateBreadcrumb(data.node.key);
|
||||
});
|
||||
},
|
||||
clickPaging: function(event, data) {
|
||||
// Load the next page of results
|
||||
var source = $.extend(
|
||||
true,
|
||||
{},
|
||||
data.node.parent.lastSourceOpts
|
||||
);
|
||||
source.data.offset = data.node.parent.countChildren() - 1;
|
||||
data.node.replaceWith(source);
|
||||
},
|
||||
});
|
||||
|
||||
$("#searchResultTree").fancytree({
|
||||
extensions: ["table", "wide"],
|
||||
source: [{ title: "No Results." }],
|
||||
minExpandLevel: 2,
|
||||
icon: false,
|
||||
table: {
|
||||
nodeColumnIdx: 2,
|
||||
},
|
||||
postProcess: function(event, data) {
|
||||
var response = data.response;
|
||||
|
||||
data.node.info("search postProcess", response);
|
||||
data.result = $.map(response.results, function(o) {
|
||||
var res = $.extend(
|
||||
{
|
||||
title: o.scientificName,
|
||||
key: o.key,
|
||||
},
|
||||
o
|
||||
);
|
||||
return res;
|
||||
});
|
||||
// Append paging link
|
||||
if (
|
||||
response.count != null &&
|
||||
response.offset + response.limit < response.count
|
||||
) {
|
||||
data.result.push({
|
||||
title:
|
||||
"(" +
|
||||
(response.count -
|
||||
response.offset -
|
||||
response.limit) +
|
||||
" more)",
|
||||
statusNodeType: "paging",
|
||||
});
|
||||
}
|
||||
data.node.info("search postProcess 2", data.result);
|
||||
},
|
||||
// loadChildren: function(event, data) {
|
||||
// $("#searchResultTree td div.cell").truncate({
|
||||
// multiline: true
|
||||
// });
|
||||
// },
|
||||
renderColumns: function(event, data) {
|
||||
var i,
|
||||
node = data.node,
|
||||
$tdList = $(node.tr).find(">td"),
|
||||
cnList = node.data.vernacularNames
|
||||
? $.map(node.data.vernacularNames, function(o) {
|
||||
return o.vernacularName;
|
||||
})
|
||||
: [];
|
||||
|
||||
i = 0;
|
||||
function _setCell($cell, text) {
|
||||
$("<div class='truncate'>")
|
||||
.attr("title", text)
|
||||
.text(text)
|
||||
.appendTo($cell);
|
||||
}
|
||||
$tdList.eq(i++).text(node.key);
|
||||
$tdList.eq(i++).text(node.data.rank);
|
||||
i++; // #1: node.title = scientificName
|
||||
// $tdList.eq(i++).text(cnList.join(", "));
|
||||
_setCell($tdList.eq(i++), cnList.join(", "));
|
||||
$tdList.eq(i++).text(node.data.canonicalName);
|
||||
// $tdList.eq(i++).text(node.data.accordingTo);
|
||||
_setCell($tdList.eq(i++), node.data.accordingTo);
|
||||
$tdList.eq(i++).text(node.data.taxonomicStatus);
|
||||
$tdList.eq(i++).text(node.data.nameType);
|
||||
$tdList.eq(i++).text(node.data.numOccurrences);
|
||||
$tdList.eq(i++).text(node.data.numDescendants);
|
||||
// $tdList.eq(i++).text(node.data.authorship);
|
||||
_setCell($tdList.eq(i++), node.data.authorship);
|
||||
// $tdList.eq(i++).text(node.data.publishedIn);
|
||||
_setCell($tdList.eq(i++), node.data.publishedIn);
|
||||
},
|
||||
activate: function(event, data) {
|
||||
if (data.node.isStatusNode()) {
|
||||
return;
|
||||
}
|
||||
_delay("activateNode", 500, function() {
|
||||
updateItemDetails(data.node.key);
|
||||
updateBreadcrumb(data.node.key);
|
||||
});
|
||||
},
|
||||
clickPaging: function(event, data) {
|
||||
// Load the next page of results
|
||||
var source = $.extend(
|
||||
true,
|
||||
{},
|
||||
searchResultTree.lastSourceOpts
|
||||
);
|
||||
source.data.offset = data.node.parent.countChildren() - 1;
|
||||
data.node.replaceWith(source);
|
||||
},
|
||||
});
|
||||
|
||||
taxonTree = $.ui.fancytree.getTree("#taxonTree");
|
||||
searchResultTree = $.ui.fancytree.getTree("#searchResultTree");
|
||||
|
||||
// Bind a callback that executes when document.location.hash changes.
|
||||
// (This code uses bbq: https://github.com/cowboy/jquery-bbq)
|
||||
$(window).on("hashchange", function(e) {
|
||||
var key = $.bbq.getState("key");
|
||||
console.log("bbq key", key);
|
||||
if (key) {
|
||||
updateBreadcrumb(key, true);
|
||||
}
|
||||
}); // don't trigger now, since we need the the taxonTree root nodes to be loaded first
|
||||
|
||||
$("input[name=query]")
|
||||
.on("keyup", function(e) {
|
||||
var query = $.trim($(this).val()),
|
||||
lastQuery = $(this).data("lastQuery");
|
||||
|
||||
if ((e && e.which === $.ui.keyCode.ESCAPE) || query === "") {
|
||||
$("#btnResetSearch").click();
|
||||
return;
|
||||
}
|
||||
if (e && e.which === $.ui.keyCode.ENTER && query.length >= 2) {
|
||||
$("#btnSearch").click();
|
||||
return;
|
||||
}
|
||||
if (query === lastQuery || query.length < 2) {
|
||||
console.log("Ignored query '" + query + "'");
|
||||
return;
|
||||
}
|
||||
$(this).data("lastQuery", query);
|
||||
_delay("search", 1, function() {
|
||||
$("#btnSearch").click();
|
||||
});
|
||||
$("#btnResetSearch").attr("disabled", query.length === 0);
|
||||
$("#btnSearch").attr("disabled", query.length < 2);
|
||||
})
|
||||
.focus();
|
||||
|
||||
$("#btnResetSearch").click(function(e) {
|
||||
$("#searchResultPane").collapse("hide");
|
||||
$("input[name=query]").val("");
|
||||
searchResultTree.clear();
|
||||
updateControls();
|
||||
});
|
||||
|
||||
$("#btnSearch")
|
||||
.click(function(event) {
|
||||
$("#searchResultPane").collapse("show");
|
||||
search($("input[name=query]").val());
|
||||
})
|
||||
.attr("disabled", true);
|
||||
|
||||
$("#btnPin").click(function(event) {
|
||||
taxonTree.filterBranches(function(n) {
|
||||
return n.isActive();
|
||||
});
|
||||
updateControls();
|
||||
});
|
||||
|
||||
$("#btnUnpin").click(function(event) {
|
||||
taxonTree.clearFilter();
|
||||
updateControls();
|
||||
});
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
}); // end of pageload handler
|
||||
})(jQuery, window, document);
|
||||
Reference in New Issue
Block a user