PageSourceSearch

https://pdb101.rcsb.org/js/common.js

js rcsb.org collected 2026-09-24 08:31:55 UTC 8,689 bytes, 269 lines download raw bytes

1/*
2 * common pdb101 js functions
3 *
4 *  note: for reference these are the bootstrap container width definitions:
5 *
6 *        Extra small devices (phones, less than 768px)
7 *        Small devices       (tablets, 768px and up)          @media (min-width: @screen-sm-min) { ... }
8 *        Medium devices      (desktops, 992px and up)         @media (min-width: @screen-md-min) { ... }
9 *        Large devices       (large desktops, 1200px and up)  @media (min-width: @screen-lg-min) { ... }
10 */
11
12var autosuggestFocus
13
14
15$(document).ready(function() {
16    // Purpose: Removes the .open (via Bootstrap JS onclick event) from dropdown menu when hover changes
17    // Start watching for click events as soon as the page is done loading
18    // this functionality is only in effect when horizontal navabar is displayed - applies to sm, md and large devices
19    // - TODO need more accurate way to determine this - check for class? - as value of $('#main_content').width() does not correspond to break point
20    $('.dropdown').mouseenter(function(event){
21        if ($('#main_content').width() >= 720) {
22            $(this).addClass("open");
23        }
24    });
25    $('.dropdown').mouseleave(function(event){
26        if ($('#main_content').width() >= 720) {
27            $('.dropdown').removeClass("open");
28        }
29    });
30
31    // added for tooltips
32    if ($('[data-toggle="tooltip"]')) {
33        try {
34            $('[data-toggle="tooltip"]').tooltip();
35        } catch(e) {
36            //added try/catch for pages displaying in-line jmols - remove after refactoring to place jmols in iframe
37            console.log(e)
38        }
39    }
40
41    // added for ekko lightbox
42    $(document).delegate('*[data-toggle="lightbox"]', 'click', function(event) {
43        event.preventDefault()
44        $(this).ekkoLightbox()
45    });
46
47    try {
48        $('.carousel').carousel({ interval: 5000 })
49    } catch(e) {
50        console.log(e)
51    }
52
53    // function for safari, which does not support the html5 'required' property on form input fields
54    // - note that this does not validate checkbox and radio fields
55    $("form").submit(function(e) {
56        var ref = $(this).find("[required]");
57        $(ref).each(function(){
58            if ( $(this).val() == '' ) {
59                alert("Please fill out this field.");
60                $(this).focus();
61                e.preventDefault();
62                return false;
63            }
64        });  return true;
65    });
66
67    try {
68        var queryInput = document.getElementById('query-input')
69        var autosuggestItems = document.getElementById('autosuggest-items')
70
71        queryInput.addEventListener('input', function(e) {
72                var div, i, val = this.value
73                if (!val) return false
74
75                $.getJSON('/search/suggest/' + val, function(data) {
76                    //console.log(data)
77                    closeList(autosuggestItems) // close already open list
78                    autosuggestFocus = -1
79
80                    // for each item in arr
81                    for (i = 0; i < data.length; i++) {
82                        // create DIV for each item
83                        div = document.createElement('DIV')
84                        div.innerHTML = data[i]
85
86                        // execute a function when someone clicks on the item value (DIV element)
87                        div.addEventListener('click', function(e) {
88                            // insert the autosuggest value into the query input
89                            queryInput.value = this.innerHTML
90                            doSearch()
91                        })
92                        autosuggestItems.appendChild(div)
93                    }
94                })
95            })
96
97        // handle keydown event
98        queryInput.addEventListener('keydown', function(e) {
99            var arr = autosuggestItems.getElementsByTagName('div')
100
101            if (e.key === 'ArrowDown') {
102                autosuggestFocus++
103                addActive(arr) // make the current item active
104            } else if (e.key === 'ArrowUp') {
105                autosuggestFocus--
106                addActive(arr) // make the current item active
107            } else if (e.key === 'Enter') {
108                e.preventDefault() // prevent the form from being submitted
109                if (autosuggestFocus > -1) {
110                    if (arr) arr[autosuggestFocus].click() // simulate a click on the active item
111                }
112            }
113        })
114
115    } catch(e) {
116        console.log(e)
117    }
118
119    trackUserAction()
120}
120)
121
122// classify an item as 'active'
123function addActive(arr) {
124    if (!arr) return false
125
126    // remove 'active' class on all items
127    //removeActive(arr)
128
129    if (autosuggestFocus >= arr.length) autosuggestFocus = 0
130    if (autosuggestFocus < 0) autosuggestFocus = (arr.length - 1)
131
132    // add class 'autosuggest-active'
133    //arr[autosuggestFocus].classList.add('autosuggest-active')
134
135
136    for (var i = 0; i < arr.length; i++) {
137        if (i === autosuggestFocus) arr[i].classList.add('autosuggest-active')
138        else arr[i].classList.remove('autosuggest-active')
139    }
140
141
142
143}
144
145// remove the 'autosuggest-active' class from all items in arr
146function removeActive(arr) {
147    for (var i = 0; i < arr.length; i++) {
148        arr[i].classList.remove('autosuggest-active')
149    }
150}
151
152// empty autosuggest items list
153function closeList(parent) {
154    while (parent.firstChild) parent.removeChild(parent.firstChild)
155}
156
157// run search
158function doSearch() {
159    $("#searchForm").submit();
160}
161
162// get cookie
163function getCookie(name) {
164    var name = name + '='
165    var decodedCookie = decodeURIComponent(document.cookie)
166    var ca = decodedCookie.split(';')
167    for(var i = 0; i < ca.length; i++) {
168        var c = ca[i].trim()
169        if (c.indexOf(name) === 0) {
170            return c.substring(name.length, c.length)
171        }
172    }
173    return ''
174}
175
176// get cookie
177function setCookie(name, value) {
178    document.cookie = name + '=' + value + ';'
179}
180
181// submit pdf|stl|tif download data to pdb101-reports, using proxy url to avoid https|cors issues
182function submitUserAction(data) {
183    // submit data
184    $.ajax({
185        type: 'POST',
186        url: '/user-action',
187        data
188    }).done(function(res) {
189        //console.log(res)
190    })
191}
192
193// toggle between grid and list view
194function toggleGridListView(mode) {
195    var inactiveMode = (mode == 'grid') ? 'list' : 'grid';
196    $('#' + mode + '-btn').addClass('active');
197    $('#' + inactiveMode + '-btn').removeClass('active');
198    $('.' + mode + '-view').show();
199    $('.' + inactiveMode + '-view').hide();
200}
201
202/*
203    add click handler to links to cdn for all pdf, tif, and stl files
204
205    note: added "$(this).attr('target', '_blank')" to  pdf, tif, and stl links to fix Firefox bug that prevented tracking multiple clicks on a single page
206*/
207function trackUserAction() {
208    $('body').find('a').map(function() {
209        var   href = this.href
210            , hrefLc = href.toLowerCase()
211            , cdnUrl = 'cdn.rcsb.org/pdb101'
212            // [http|https]://cdn.rcsb.org/pdb101/learn/resources/antibody/antibody-paper-model.pdf
213            , index = hrefLc.indexOf(cdnUrl)
214
215        if (index !== -1) {
216            href = href.substring(index + cdnUrl.length)
217            if (href.length) {
218                var type
219
220                if (hrefLc.indexOf('.pdf') != -1) type = 'pdf'
221                else if (hrefLc.indexOf('.tif') != -1) type = 'tif'
222                else if (hrefLc.indexOf('.stl') != -1) type = 'stl'
223
224                if (type) {
225                    var path = window.location.pathname
226                    var data = { href, type, path }
227                    $(this).attr('target', '_blank')
228                    $(this).click( () => submitUserAction(data) )
229                }
230            }
231        }
232    })
233}
234
235// validate search
236function validateQueryInput() {
237    if ($('#query-input').val().trim() === '') {
238        alert('Please enter a value in the search field.')
239        $('#query-input').focus()
240        return false
241    }
242    return true
243}
244
245/*!
246 * IE10 viewport hack for Surface/desktop Windows 8 bug
247 * Copyright 2014-2015 Twitter, Inc.
248 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
249 *
250 * See the Getting Started docs for more information:
251 * http://getbootstrap.com/getting-started/#support-ie10-width
252 */
253(function () {
254  'use strict';
255  if (navigator.userAgent.match(/IEMobile\/10\.0/)) {
256    var msViewportStyle = document.createElement('style')
257    msViewportStyle.appendChild(
258      document.createTextNode(
259        '@-ms-viewport{width:auto!important}'
260      )
261    )
262    document.querySelector('head').appendChild(msViewportStyle)
263  }
264})();
265
266
267
268
269

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.