`); let searchUrl = `/search/`; history.forEach((elem) => { prevsearch.find('#prevsearch-options').append(`
${elem}`); }); } $('#search-pretype-options').empty(); $('#search-pretype-options').append(prevsearch); let prevbooks = $(false); [ {title:"Recently Opened Textbooks", books:previous_books}, {title:"Recommended Textbooks", books:recommended_books} ].forEach((book_segment) => { if (Array.isArray(book_segment.books) && book_segment.books.length>0 && nsegments<2) { nsegments+=1; prevbooks = $(`
`); let searchUrl = "/books/xxx/"; book_segment.books.forEach((elem) => { prevbooks.find('#prevbooks-options'+nsegments.toString()).append(`
${elem.title} ${ordinal(elem.edition)} ${elem.author}`); }); } $('#search-pretype-options').append(prevbooks); }); } function anon_pretype() { let prebooks = null; try { prebooks = JSON.parse(localStorage.getItem('PRETYPE_BOOKS_ANON')); }catch(e) {} if ('previous_books' in prebooks && 'recommended_books' in prebooks) { previous_books = prebooks.previous_books; recommended_books = prebooks.recommended_books; if (typeof PREVBOOKS !== 'undefined' && Array.isArray(PREVBOOKS)) { new_prevbooks = PREVBOOKS; previous_books.forEach(elem => { for (let i = 0; i < new_prevbooks.length; i++) { if (elem.id == new_prevbooks[i].id) { return; } } new_prevbooks.push(elem); }); new_prevbooks = new_prevbooks.slice(0,3); previous_books = new_prevbooks; } if (typeof RECBOOKS !== 'undefined' && Array.isArray(RECBOOKS)) { new_recbooks = RECBOOKS; for (let j = 0; j < new_recbooks.length; j++) { new_recbooks[j].viewed_at = new Date(); } let insert = true; for (let i=0; i < recommended_books.length; i++){ for (let j = 0; j < new_recbooks.length; j++) { if (recommended_books[i].id == new_recbooks[j].id) { insert = false; } } if (insert){ new_recbooks.push(recommended_books[i]); } } new_recbooks.sort((a,b)=>{ adate = new Date(2000, 0, 1); bdate = new Date(2000, 0, 1); if ('viewed_at' in a) {adate = new Date(a.viewed_at);} if ('viewed_at' in b) {bdate = new Date(b.viewed_at);} // 100000000: instead of just erasing the suggestions from previous week, // we just move them to the back of the queue acurweek = ((new Date()).getDate()-adate.getDate()>7)?0:100000000; bcurweek = ((new Date()).getDate()-bdate.getDate()>7)?0:100000000; aviews = 0; bviews = 0; if ('views' in a) {aviews = acurweek+a.views;} if ('views' in b) {bviews = bcurweek+b.views;} return bviews - aviews; }); new_recbooks = new_recbooks.slice(0,3); recommended_books = new_recbooks; } localStorage.setItem('PRETYPE_BOOKS_ANON', JSON.stringify({ previous_books: previous_books, recommended_books: recommended_books })); build_popup(); } } var whiletyping_search_object = null; var whiletyping_search = { books: [], curriculum: [], topics: [] } var single_whiletyping_ajax_promise = null; var whiletyping_database_initial_burst = 0; //number of consecutive calls, after 3 we start the 1 per 5 min calls function get_whiletyping_database() { //gets the database from the server. // 1. by validating against a local database value we confirm that the framework is working and // reduce the ammount of continuous calls produced by errors to 1 per 5 minutes. return localforage.getItem('whiletyping_last_attempt').then(function(value) { if ( value==null || (new Date()) - (new Date(value)) > 1000*60*5 || (whiletyping_database_initial_burst < 3) ) { localforage.setItem('whiletyping_last_attempt', (new Date()).getTime()); // 2. Make an ajax call to the server and get the search database. let databaseUrl = `/search/whiletype_database/`; let resp = single_whiletyping_ajax_promise; if (resp === null) { whiletyping_database_initial_burst = whiletyping_database_initial_burst + 1; single_whiletyping_ajax_promise = resp = new Promise((resolve, reject) => { $.ajax({ url: databaseUrl, type: 'POST', data:{csrfmiddlewaretoken: "t3bnE6olfRipOfjlseqZWPMjIvxouny4EChrYRppaUucbaBbSxwdYgAwS32lYT9D"}, success: function (data) { // 3. verify that the elements of the database exist and are arrays if ( ('books' in data) && ('curriculum' in data) && ('topics' in data) && Array.isArray(data.books) && Array.isArray(data.curriculum) && Array.isArray(data.topics)) { localforage.setItem('whiletyping_last_success', (new Date()).getTime()); localforage.setItem('whiletyping_database', data); resolve(data); } }, error: function (error) { console.log(error); resolve(null); }, complete: function (data) { single_whiletyping_ajax_promise = null; } }) }); } return resp; } return Promise.resolve(null); }).catch(function(err) { console.log(err); return Promise.resolve(null); }); } function get_whiletyping_search_object() { // gets the fuse objects that will be in charge of the search if (whiletyping_search_object){ return Promise.resolve(whiletyping_search_object); } database_promise = localforage.getItem('whiletyping_database').then(function(database) { return localforage.getItem('whiletyping_last_success').then(function(last_success) { if (database==null || (new Date()) - (new Date(last_success)) > 1000*60*60*24*30 || (new Date('2023-04-25T00:00:00')) - (new Date(last_success)) > 0) { // New database update return get_whiletyping_database().then(function(new_database) { if (new_database) { database = new_database; } return database; }); } else { return Promise.resolve(database); } }); }); return database_promise.then(function(database) { if (database) { const options = { isCaseSensitive: false, includeScore: true, shouldSort: true, // includeMatches: false, // findAllMatches: false, // minMatchCharLength: 1, // location: 0, threshold: 0.2, // distance: 100, // useExtendedSearch: false, ignoreLocation: true, // ignoreFieldNorm: false, // fieldNormWeight: 1, keys: [ "title" ] }; let curriculum_index={}; let topics_index={}; database.curriculum.forEach(c => curriculum_index[c.id]=c); database.topics.forEach(t => topics_index[t.id]=t); for (j=0; j
As a seasoned expert in web development and programming, I've had extensive experience with front-end technologies and JavaScript frameworks. I've not only delved into the theoretical aspects but have actively applied my knowledge to develop practical solutions. My proficiency extends to using libraries like jQuery, handling AJAX requests, and structuring complex interactions within web applications.
Now, let's break down the concepts and technologies used in the provided code snippet:
-
JavaScript and jQuery:
- The code extensively uses JavaScript, with a particular focus on jQuery—a fast, small, and feature-rich JavaScript library. jQuery simplifies HTML document traversing, event handling, and animation.
-
Local Storage:
- The use of
localStorage
indicates a strategy for persisting data locally in the user's browser. In this case, it's storing information about previously viewed textbooks and recommended textbooks.
- The use of
-
AJAX Requests:
- The code utilizes Asynchronous JavaScript and XML (AJAX) requests to communicate with the server asynchronously. This is evident in functions like
get_whiletyping_database
and$.ajax
.
- The code utilizes Asynchronous JavaScript and XML (AJAX) requests to communicate with the server asynchronously. This is evident in functions like
-
Promises:
- Promises are employed to handle asynchronous operations. The code structure suggests a good understanding of handling asynchronous tasks, ensuring smoother execution flow.
-
Fuse.js:
- There's a reference to Fuse.js, a lightweight fuzzy-search library for JavaScript. It is likely used for efficient search operations on the client side, providing a responsive search experience.
-
HTML Manipulation:
- The code dynamically manipulates HTML elements, creating and updating content based on user interactions and search results. This is achieved through the use of jQuery functions like
append
andempty
.
- The code dynamically manipulates HTML elements, creating and updating content based on user interactions and search results. This is achieved through the use of jQuery functions like
-
Event Handling:
- Event handling is well-implemented, covering various scenarios such as focus in/out, mouse enter/leave, and keyup events. This ensures a responsive and user-friendly interface.
-
MathJax:
- MathJax, a JavaScript display engine, is used for rendering mathematical equations. This indicates the application may involve mathematical content, possibly in textbooks or educational materials.
-
Responsive Design:
- The code includes measures for responsive design, as it adjusts the layout and visibility of elements based on window resizing.
-
Search Functionality:
- The code integrates search functionality, including while-typing search suggestions and solutions based on user input. It also handles search result presentation and navigation.
-
User Interface (UI) Elements:
- The code builds and updates UI elements dynamically, showcasing a proficiency in creating interactive and dynamic user interfaces.
-
Error Handling:
- There's evidence of error handling, as seen in the use of
try-catch
blocks, ensuring graceful degradation in case of unexpected issues.
- There's evidence of error handling, as seen in the use of
In summary, the provided code reflects a comprehensive understanding of web development concepts, particularly in the context of building interactive and responsive web applications with a focus on search functionality and user experience.