main.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. define([
  2. 'require',
  3. 'base/js/namespace',
  4. 'base/js/events',
  5. 'jquery'
  6. ], function(
  7. requirejs,
  8. Jupyter,
  9. events,
  10. $
  11. ) {
  12. var have_bs_tooltips = false;
  13. var mod_name = "mickaSearch";
  14. var log_prefix = `[${mod_name}] `;
  15. var side_panel_min_rel_width = 10;
  16. var side_panel_max_rel_width = 90;
  17. var side_panel_start_width = 45;
  18. var load_next;
  19. var cfg = {
  20. //'micka_url': 'https://hub.lesprojekt.cz/micka/',
  21. 'micka_url': '',
  22. //'proxy_url': 'https://cors-anywhere.herokuapp.com/'
  23. 'proxy_url': ''
  24. };
  25. //read user configuration
  26. var read_config = function () {
  27. var config = IPython.notebook.config;
  28. for (var key in cfg) {
  29. if (config.data.mickaSearch.hasOwnProperty(key))
  30. cfg[key] = config.data.mickaSearch[key];
  31. }
  32. };
  33. //copy text to clipboard
  34. cc = function (text) {
  35. navigator.clipboard.writeText(text).then(function() {
  36. /* clipboard successfully set */
  37. }, function() {
  38. /* clipboard write failed */
  39. console.log(log_prefix + 'clipboard write failed');
  40. });
  41. };
  42. // get metadata
  43. var fetch_metatada = function (search_params) {
  44. return fetch(`${cfg.proxy_url}${cfg.micka_url}csw/${search_params}`, {credentials: 'same-origin'});
  45. };
  46. // do search
  47. search_micka = function () {
  48. load_next = 1;
  49. document.getElementById('msres').innerHTML = '';
  50. document.getElementById('msnext').innerHTML = '';
  51. var query = document.getElementById('mquery').value;
  52. query = query.length > 0 ? `FullText%3D'${query}'` : '';
  53. var mdata = fetch_metatada(`?request=GetRecords&query=${query}&format=application/json&MaxRecords=9999&sortby=title%3AA&language=eng&outputSchema=http://www.w3.org/2005/Atom&typenames=gmd:MD_Metadata&StartPosition=${load_next}`);
  54. mdata.then(response => response.json())
  55. .then(arrayOfMetadata => {
  56. create_view(arrayOfMetadata.records);
  57. create_load(arrayOfMetadata.next);
  58. })
  59. .catch(error => {
  60. console.log(log_prefix + error);
  61. });
  62. };
  63. // load next page
  64. search_micka_next = function () {
  65. var query = document.getElementById('mquery').value;
  66. query = query.length > 0 ? `FullText%3D'${query}'` : '';
  67. var mdata = fetch_metatada(`?request=GetRecords&query=${query}&format=application/json&MaxRecords=9999&sortby=title%3AA&language=eng&outputSchema=http://www.w3.org/2005/Atom&typenames=gmd:MD_Metadata&StartPosition=${load_next}`);
  68. mdata.then(response => response.json())
  69. .then(arrayOfMetadata => {
  70. create_view(arrayOfMetadata.records);
  71. create_load(arrayOfMetadata.next);
  72. })
  73. .catch(error => {
  74. console.log(log_prefix + error);
  75. });
  76. };
  77. // prepare and render html structure
  78. var create_view = function(data) {
  79. var output = '';
  80. data.forEach(function(entry) {
  81. output += `<details><summary>${entry.title}</summary>`;
  82. output += '<p>Type: ';
  83. output += entry.type=='application' ? `${entry.type} - Service: ${entry.serviceType}` : `${entry.type}`;
  84. output += `<br><a href="${cfg.micka_url}record/basic/${entry.id}" target="_blank" title="Full MD Record">MD Record</a>`;
  85. output += entry.abstract.length > 0 ? `<br>Abstract: ${entry.abstract}` : '';
  86. output += entry.bbox.length > 0 ? `<br>Boundig box: ${entry.bbox}` : '';
  87. output += entry.imgURL ? `<details><summary>Thumbnail</summary><img src="${entry.imgURL}" width="200" onerror="this.parentElement.style.display='none'"></details>` : '';
  88. var links = '';
  89. entry.links.forEach(function(link) {
  90. links += `<li>${link.url} <a class="mlink" onclick="cc('${link.url}');" title="Copy to clipboard"><strong>&nbsp;C&nbsp;</strong></a></li>`;
  91. });
  92. output += links.length > 0 ? `<details><summary>Links</summary><ul>${links}</ul></details>` : '';
  93. output += '</p>';
  94. output += '</details>';
  95. });
  96. document.getElementById('msres').innerHTML += output;
  97. };
  98. //check pagination, enable load next page
  99. var create_load = function (next) {
  100. if (next) {
  101. load_next += 100;
  102. document.getElementById('msnext').innerHTML = `<button onclick="search_micka_next()">More</button>`;
  103. } else {
  104. document.getElementById('msnext').innerHTML = '';
  105. }
  106. }
  107. /////////////////////////////////
  108. var build_side_panel = function (main_panel, side_panel, min_rel_width, max_rel_width) {
  109. if (min_rel_width === undefined) min_rel_width = 0;
  110. if (max_rel_width === undefined) max_rel_width = 100;
  111. side_panel.css('display','none');
  112. side_panel.insertAfter(main_panel);
  113. var side_panel_splitbar = $('<div class="side_panel_splitbar"/>');
  114. var side_panel_inner = $('<div class="side_panel_inner"/>');
  115. var side_panel_expand_contract = $('<i class="btn fa fa-expand hidden-print">');
  116. side_panel.append(side_panel_splitbar);
  117. side_panel.append(side_panel_inner);
  118. side_panel_inner.append(side_panel_expand_contract);
  119. side_panel_expand_contract.attr({
  120. title: 'expand/contract panel',
  121. 'data-toggle': 'tooltip'
  122. }).tooltip({
  123. placement: 'right'
  124. }).click(function () {
  125. var open = $(this).hasClass('fa-expand');
  126. var site = $('#site');
  127. slide_side_panel(main_panel, side_panel,
  128. open ? 100 : side_panel.data('last_width') || side_panel_start_width);
  129. $(this).toggleClass('fa-expand', !open).toggleClass('fa-compress', open);
  130. var tooltip_text = (open ? 'shrink to not' : 'expand to') + ' fill the window';
  131. if (open) {
  132. side_panel.insertAfter(site);
  133. site.slideUp();
  134. $('#header').slideUp();
  135. side_panel_inner.css({'margin-left': 0});
  136. side_panel_splitbar.hide();
  137. }
  138. else {
  139. side_panel.insertAfter(main_panel);
  140. $('#header').slideDown();
  141. site.slideDown({
  142. complete: function() { events.trigger('resize-header.Page'); }
  143. });
  144. side_panel_inner.css({'margin-left': ''});
  145. side_panel_splitbar.show();
  146. }
  147. if (have_bs_tooltips) {
  148. side_panel_expand_contract.attr('title', tooltip_text);
  149. side_panel_expand_contract.tooltip('hide').tooltip('fixTitle');
  150. }
  151. else {
  152. side_panel_expand_contract.tooltip('option', 'content', tooltip_text);
  153. }
  154. });
  155. // bind events for resizing side panel
  156. side_panel_splitbar.mousedown(function (md_evt) {
  157. md_evt.preventDefault();
  158. $(document).mousemove(function (mm_evt) {
  159. mm_evt.preventDefault();
  160. var pix_w = side_panel.offset().left + side_panel.outerWidth() - mm_evt.pageX;
  161. var rel_w = 100 * (pix_w) / side_panel.parent().width();
  162. rel_w = rel_w > min_rel_width ? rel_w : min_rel_width;
  163. rel_w = rel_w < max_rel_width ? rel_w : max_rel_width;
  164. main_panel.css('width', (100 - rel_w) + '%');
  165. side_panel.css('width', rel_w + '%').data('last_width', rel_w);
  166. });
  167. return false;
  168. });
  169. $(document).mouseup(function (mu_evt) {
  170. $(document).unbind('mousemove');
  171. });
  172. return side_panel;
  173. };
  174. var slide_side_panel = function (main_panel, side_panel, desired_width) {
  175. var anim_opts = {
  176. step : function (now, tween) {
  177. main_panel.css('width', 100 - now + '%');
  178. }
  179. };
  180. if (desired_width === undefined) {
  181. if (side_panel.is(':hidden')) {
  182. desired_width = (side_panel.data('last_width') || side_panel_start_width);
  183. }
  184. else {
  185. desired_width = 0;
  186. }
  187. }
  188. var visible = desired_width > 0;
  189. if (visible) {
  190. main_panel.css({float: 'left', 'overflow-x': 'auto'});
  191. side_panel.show();
  192. }
  193. else {
  194. anim_opts.complete = function () {
  195. side_panel.hide();
  196. main_panel.css({float : '', 'overflow-x': '', width: ''});
  197. };
  198. }
  199. side_panel.animate({width: desired_width + '%'}, anim_opts);
  200. return visible;
  201. };
  202. var populate_side_panel = function(side_panel) {
  203. var side_panel_inner = side_panel.find('.side_panel_inner');
  204. var inner_content = `<div id="msform">
  205. <input type="text" id="mquery" onfocus="Jupyter.keyboard_manager.disable()" onfocusout="Jupyter.keyboard_manager.enable()">
  206. <button onclick="search_micka();Jupyter.keyboard_manager.enable()" id="msBtn">Search</button>
  207. </div>
  208. <div id="msres"></div>
  209. <div id="msnext"></div>
  210. <script>
  211. var msinput = document.getElementById("mquery");
  212. msinput.addEventListener("keyup", function(event) {
  213. if (event.keyCode === 13) {
  214. event.preventDefault();
  215. document.getElementById("msBtn").click();
  216. msinput.blur();
  217. }
  218. });
  219. </script>`;
  220. side_panel_inner.append(inner_content);
  221. };
  222. var toggleSearchPanel = function () {
  223. var main_panel = $('#notebook_panel');
  224. var side_panel = $('#side_panel');
  225. if (side_panel.length < 1) {
  226. side_panel = $('<div id="side_panel"/>');
  227. build_side_panel(main_panel, side_panel,
  228. side_panel_min_rel_width, side_panel_max_rel_width);
  229. populate_side_panel(side_panel);
  230. }
  231. var visible = slide_side_panel(main_panel, side_panel);
  232. //if (params.help_panel_add_toolbar_button) {
  233. $('#btn_msearch').toggleClass('active', visible);
  234. //}
  235. return visible;
  236. };
  237. ////////////////////////////////
  238. var initialize = function () {
  239. read_config();
  240. var handler = function () {
  241. var visible = toggleSearchPanel();
  242. };
  243. var action = {
  244. icon: 'fa-search',
  245. help : 'Micka Search',
  246. help_index : 'zz',
  247. label: 'Micka',
  248. handler : handler,
  249. id: 'btn_msearch'
  250. };
  251. var prefix = 'micka_search';
  252. var action_name = 'micka-search';
  253. var full_action_name = Jupyter.actions.register(action, action_name, prefix);
  254. Jupyter.toolbar.add_buttons_group([full_action_name]);
  255. console.log(log_prefix + 'button added');
  256. };
  257. var load_ipython_extension = function() {
  258. $('head').append(
  259. $('<link/>', {
  260. rel: 'stylesheet',
  261. type:'text/css',
  262. href: requirejs.toUrl('./search_panel.css')
  263. })
  264. );
  265. return IPython.notebook.config.loaded.then(initialize);
  266. };
  267. return {
  268. load_ipython_extension: load_ipython_extension
  269. };
  270. });