1. Trang chủ
  2. » Công Nghệ Thông Tin

Practical Web 2.0 Applications with PHP phần 9 pdf

60 372 1

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 60
Dung lượng 1,41 MB

Nội dung

{ var json = transport.responseText.evalJSON(true); this.showSuggestions(json); }, showSuggestions : function(suggestions) { this.clearSuggestions(); if (suggestions.size() == 0) return; var ul = Builder.node('ul'); for (var i = 0; i < suggestions.size(); i++) { var li = $(Builder.node('li')); li.update(suggestions[i]); ul.appendChild(li); } this.container.appendChild(ul); }, Another thing we do in the showSuggestions() function is clear any existing terms before new ones are shown. We do this using clearSuggestions(), which is shown in Listing 12-37. This is called regardless of whether any search suggestions have been found; if there are no suggestions, there is nothing to show, and if there are suggestions, then we want to show only the new ones, not ones that were previously there. Listing 12-37. Removing Existing Search Suggestions from the Search Container (SearchSuggestor.class.js) clearSuggestions : function() { this.container.getElementsBySelector('ul').each(function(e) { e.remove(); }); this.query = null; } }; One more minor change we must now make is to the loadSuggestions() function. Cur- rently in this function if the search term is empty, then we don’t bother performing this Ajax request. We must now make it so in addition to not performing the Ajax request, the current list of suggestions is hidden. The reason we add this is because if the user highlights the search input and presses Backspace, the term would be deleted but the suggestions would remain. The code in Listing 12-38 fixes this issue. CHAPTER 12 ■ IMPLEMENTING SITE SEARCH 459 9063Ch12CMP3 11/13/07 9:26 PM Page 459 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Listing 12-38. Clearing Suggestions When the Search Term Is Cleared (SearchSuggestor.class.js) loadSuggestions : function() { var query = $F(this.input).strip(); if (query.length == 0) this.clearSuggestions(); if (query.length == 0 || query == this.query) return; // other code }, Adding Mouse Navigation to Results Although the search suggestions are now being displayed when the user begins to enter a search term, it is not yet possible to do anything useful with these suggestions. The first thing we are going to do is allow users to click one of the suggestions. This will trigger the search form being submitted using the selected term. To do so, we must first handle the mouseover, mouseout, and click events for each list item. The functionality we want to occur for each event is as follows: • When the mouse is over a suggestion, highlight the suggestion. We do this by creating a new CSS style called .active and adding it using the Prototype addClassName() method. • When the mouse moves away from a suggestion, remove the .active class using removeClassName(). • When a search term is clicked, replace the term currently in the search input with the clicked term and then submit the form. First, we will add the new CSS style. We will simply make the active item display with a red background and white text. Listing 12-39 shows the new CSS selector we add to styles.css. Listing 12-39. Styling the Active Search Suggestion (styles.css) #search li.active { background : #f22; color : #fff; cursor : pointer; } Now we use the observe() method to handle the three events discussed earlier. Listing 12-40 shows the code we add to the showSuggestions() function to observe these events, as well as the suggestionClicked() function that we call from within the click event. CHAPTER 12 ■ IMPLEMENTING SITE SEARCH460 9063Ch12CMP3 11/13/07 9:26 PM Page 460 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Listing 12-40. Handling the Mouse Events with the Search Suggestions (SearchSuggestor.class.js) // other code showSuggestions : function(suggestions) { this.clearSuggestions(); if (suggestions.size() == 0) return; var ul = Builder.node('ul'); for (var i = 0; i < suggestions.size(); i++) { var li = $(Builder.node('li')); li.update(suggestions[i]); li.observe('mouseover', function(e) { Event.element(e).addClassName('active') }); li.observe('mouseout', function(e) { Event.element(e).removeClassName('active') }); li.observe('click', this.suggestionClicked.bindAsEventListener(this)); ul.appendChild(li); } this.container.appendChild(ul); }, suggestionClicked : function(e) { var elt = Event.element(e); var term = elt.innerHTML.strip(); this.input.value = term; this.input.form.submit(); this.clearSuggestions(); }, // other code CHAPTER 12 ■ IMPLEMENTING SITE SEARCH 461 9063Ch12CMP3 11/13/07 9:26 PM Page 461 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com As you can see, in the suggestionClicked() event handler, the first thing we do is determine which suggestion was clicked using the Event.element() function. We can then determine what the search term is by retrieving the innerHTML property of the element (we also use strip() to clean up this code in case extra whitespace is added to it). We then update the value of the form element and submit the form. Additionally, we clear the suggestions after one has been clicked, preventing the user from clicking a different sug- gestion while the form is being submitted. Adding Keyboard Navigation to Results The final thing we do to improve the search suggestions is to add keyboard controls to the sug- gestions. Essentially what we want to be able to do is let the user choose a suggestion using their up and down arrow keys. The keyboard handling rules we will add are as follows: •If the user presses the down arrow and no term has been highlighted (that is, set to use the .active class), then select the first term. •If the user presses the down arrow and a suggestion is highlighted, move to the next suggestion. If the user presses down when the last suggestion is highlighted, then select no suggestion so the user can hit Enter on what they have typed so far. •If the user presses up and no term is selected, then select the last suggestion. •If the user presses up and a suggestion is highlighted, move to the previous suggestion. Select no suggestion if up is pressed when the first suggestion is selected. •Submit the search form with the highlighted term when Enter is pressed. •Hide the suggestions if the Escape key is pressed. As you can probably tell, the work involved with adding keyboard controls is slightly more involved than adding mouse controls. The first thing we are going to do is to write some utility functions to help us select items and to determine which item is selected. Listing 12-41 shows the getNumberOfSuggestions() function that we add to SearchSuggestor.class.js, which simply counts the number of list items present and returns that number. This is helpful in determining the item index of the next or previous item when using the arrow keys. Listing 12-41. Determining the Number of Suggestions Showing to the User (SearchSuggestor.class.js) SearchSuggestor = Class.create(); SearchSuggestor.prototype = { // other code CHAPTER 12 ■ IMPLEMENTING SITE SEARCH462 9063Ch12CMP3 11/13/07 9:26 PM Page 462 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com getNumberOfSuggestions : function() { return this.container.getElementsBySelector('li').size(); }, ■Note When you add this function and the other new functions in this section to SearchSuggestor.class.js, make sure the comma is correctly placed after the close brace of each func- tion in the class (except for the final one). Next we write a function to select an item (that is, to apply the .active class) based on its numerical index in the list of items. This list is zero-indexed. Listing 12-42 shows the selectSuggestion() class, which works by looping over all list items and adding the .active class if it matches the passed-in argument. Note that this function also deselects every other list item. In effect we can use this function to ensure no items are selected at all by passing an invalid index (such as -1). Listing 12-42. Selecting a Single Suggestion Based on Its Index (SearchSuggestor.class.js) selectSuggestion : function(idx) { var items = this.container.getElementsBySelector('li'); for (var i = 0; i < items.size(); i++) { if (i == idx) items[i].addClassName('active'); else items[i].removeClassName('active'); } }, Next, we write a function to determine the index of the item that is currently selected, shown in Listing 12-43. This is in some ways the opposite of the selectSuggestion() function. It works almost identically, but rather than updating the class name, it checks instead for the presence of the .active class. If no items are currently selected, then -1 is returned. Listing 12-43. Determining the Index of the Selected Suggestion (SearchSuggestor.class.js) getSelectedSuggestionIndex : function() { var items = this.container.getElementsBySelector('li'); for (var i = 0; i < items.size(); i++) { if (items[i].hasClassName('active')) return i; CHAPTER 12 ■ IMPLEMENTING SITE SEARCH 463 9063Ch12CMP3 11/13/07 9:26 PM Page 463 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com } return -1; }, Now we write a function called getSelectedSuggestion(), which is shown in Listing 12-44. This function is identical to getSelectedSuggestionIndex() except that it returns the actual search term that is selected rather than its index in the list. We will use this function when the user hits Enter while a term is selected. Listing 12-44. Determining the Search Suggestion That Is Currently Selected (SearchSuggestor.class.js) getSelectedSuggestion : function() { var items = this.container.getElementsBySelector('li'); for (var i = 0; i < items.size(); i++) { if (items[i].hasClassName('active')) return items[i].innerHTML.strip(); } return ''; } }; The final thing we must do is modify the onQueryChanged() function, which is the event handler we defined that is called whenever a key is pressed in the search input. Currently, all the function does is clear any existing timers and set a new timer for fetching suggestions. We will now add handlers for specific keys to this function (in addition to the timer-handling code). Listing 12-45 shows the code we use to handle the Enter key being pressed. When the user hits Enter, if a suggestion is highlighted, then we want to populate the search input with this term and submit the form. If no term is highlighted, then we submit the form with whatever the user has typed so far. When the search term populates the input, we clear the suggestions, just as we did in the mouse-handling code. Also, note that we leave the call to clearTimeout() in front of the switch() statement. This is because we will be returning from the keys handled in the switch() statement, but we still want to cancel the timer. All normal key presses will travel beyond the switch() statement and trigger the new timer. Listing 12-45. Searching on the Selected Term When the User Hits Enter (SearchSuggestor.class.js) SearchSuggestor = Class.create(); SearchSuggestor.prototype = { // other code CHAPTER 12 ■ IMPLEMENTING SITE SEARCH464 9063Ch12CMP3 11/13/07 9:26 PM Page 464 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com onQueryChanged : function(e) { clearTimeout(this.timer); switch (e.keyCode) { case Event.KEY_RETURN: var term = this.getSelectedSuggestion(); if (term.length > 0) { this.input.value = term; this.clearSuggestions(); } return; Next we handle the Escape key being pressed. This case is fairly simple, because all we need to do is to hide the search suggestions, as shown in Listing 12-46. Listing 12-46. Hiding the Search Suggestions When the User Hits Escape case Event.KEY_ESC: this.clearSuggestions(); return; We now handle the trickier case where the user presses the down arrow key. According to the rules we specified earlier in this section, we want to select the first term if no term is selected; otherwise, we want to select the next term. As another special case, if the last term is selected, then pressing the down arrow should result in no suggestion being selected. Listing 12-47 shows the code we use to determine which suggestion should now be selected as a result of the down arrow being pressed. We make use of the utility functions we just created to help with this. Listing 12-47. Selecting the Next Item When the Down Arrow Is Pressed (SearchSuggestor.class.js) case Event.KEY_DOWN: var total = this.getNumberOfSuggestions(); var selected = this.getSelectedSuggestionIndex(); if (selected == total - 1) // currenty last item so deselect selected = -1; else if (selected < 0) // none selected, select the first selected = 0; else // select the next selected = (selected + 1) % total; this.selectSuggestion(selected); Event.stop(e); return; CHAPTER 12 ■ IMPLEMENTING SITE SEARCH 465 9063Ch12CMP3 11/13/07 9:26 PM Page 465 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com To handle the case where the up arrow is pressed, we basically just do the opposite of the down arrow calculations. Listing 12-48 shows the code for this case. This code also includes the final call of the function to initiate the new timer. Note that this won’t be called for presses of the Enter, Escape, up arrow, and down arrow keys, because we’ve returned from each of them in this function. Listing 12-48. Selecting the Previous Suggestion When the Up Arrow Is Pressed (SearchSuggestor.class.js) case Event.KEY_UP: var total = this.getNumberOfSuggestions(); var selected = this.getSelectedSuggestionIndex(); if (selected == 0) // first item currently selected, so deselect selected = -1; else if (selected < 0) // none selected, select the last item selected = total - 1; else // select the previous selected = (selected - 1) % total; this.selectSuggestion(selected); Event.stop(e); return; } this.timer = setTimeout(this.loadSuggestions.bind(this), this.delay * 1000); }, // other code }; If you now type a search term in the search box (assuming some existing searches have already taken place), you will be shown a list of suggestions for your search, as shown in Figure 12-3. You might want to add some extra functionality to the tool in the future, such as display- ing the number of results that would be returned if the user were to perform the given search. The difficulty in providing features such as this is that they are resource intensive. You need to perform the search of each term in real time (not recommended) to determine how many results the search would return, or you need to cache the result counts so the data can be accessed quickly. In any case, you need to be aware of the implications of adding features like this to your server. Even the suggestion lookup tool as it is results in a new HTTP request and database query each time, so imagine if you had hundreds or thousands of people using the search tool at any one time. CHAPTER 12 ■ IMPLEMENTING SITE SEARCH466 9063Ch12CMP3 11/13/07 9:26 PM Page 466 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Figure 12-3. Search suggestions are now being displayed below the search input. Summary In this chapter, we created a fully functioning search engine for our web application using Zend_Search_Lucene. We achieved this by creating a search index for all of the blog posts in the application. We altered the blog management code so the index is automatically maintained when posts are created, updated, or deleted. Next we added a search form to the website to allow users to find blog posts. The powerful querying syntax of Lucene meant posts could be found based on several criteria, including the title, the body, or its tags. Finally, we improved the search form to behave similarly to Google’s Suggest interface. This provides users with some suggestions on what to search for, based on the tags registered users have applied to their blog posts. In the next chapter, we will be looking closely at Google Maps. We will extend the blog func- tionality so users can add locations to their blog posts and display those maps accordingly. CHAPTER 12 ■ IMPLEMENTING SITE SEARCH 467 9063Ch12CMP3 11/13/07 9:26 PM Page 467 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 9063Ch12CMP3 11/13/07 9:26 PM Page 468 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com [...]... action, we initialize the $ret array, which will hold the return data 4 89 9063Ch13CMP3 11/15/07 8:20 AM Page 490 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 490 CHAPTER 13 ■ INTEGRATING GOOGLE MAPS Listing 13-21 Initializing the Action Handler and Loading the Blog Post (BlogmanagerController .php) < ?php class BlogmanagerController extends CustomControllerAction { // other... the locationsmanageAction() function Listing 13-25 Processing the Move Location Request (BlogmanagerController .php) case 'move': $location_id = $request->getPost('location_id'); 491 90 63Ch13CMP3 11/15/07 8:20 AM Page 492 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 492 CHAPTER 13 ■ INTEGRATING GOOGLE MAPS $location = new DatabaseObject_BlogPostLocation($this->db); if ($location->loadForPost($post->getId(),... post 493 90 63Ch13CMP3 11/15/07 8:20 AM Page 494 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 494 CHAPTER 13 ■ INTEGRATING GOOGLE MAPS • zoomAndCenterMap(): This automatically zooms the map in as far as possible to display all of the locations This will be called when the map is initially loaded and also when a new location is added If there are no locations to work with, .. .90 63Ch13CMP3 11/15/07 8:20 AM Page 4 69 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com CHAPTER 13 Integrating Google Maps A ll of the code we have developed so far in this book has been self-contained with no reliance on any outside services Frequently in your web development endeavors you will need to integrate features... and longitude -1 22.08 1783 would be returned These coordinates can then be used to mark locations on the displayed map Google provides two ways to access its geocoder The first method is to use their JavaScript interface to look up addresses This allows you to look up and add new points on your map from within the client-side web browser 4 69 9063Ch13CMP3 11/15/07 8:20 AM Page 470 Simpo PDF Merge and Split... $this->breadcrumbs->addStep('Manage Locations'); $this->view->post = $post; } } ?> 4 79 9063Ch13CMP3 11/15/07 8:20 AM Page 480 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 480 CHAPTER 13 ■ INTEGRATING GOOGLE MAPS If you were to now view this controller action (assuming you passed in a valid blog post ID in the URL of http://phpweb20/blogmanager/preview?id=PostId), an error would be displayed... locations.tpl, stored in /templates/blogmanager The added or changed lines are highlighted accordingly 90 63Ch13CMP3 11/15/07 8:20 AM Page 493 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com CHAPTER 13 ■ INTEGRATING GOOGLE MAPS Listing 13-26 The Locations Management Template with Add Location Form (locations.tpl) {include file='header.tpl' section='blogmanager' maps=true} . 12 ■ IMPLEMENTING SITE SEARCH 467 90 6 3Ch12CMP3 11/13 /07 9 :26 PM Page 467 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 90 6 3Ch12CMP3 11/13 /07 9 :26 PM Page 468 Simpo PDF. IMPLEMENTING SITE SEARCH4 60 90 6 3Ch12CMP3 11/13 /07 9 :26 PM Page 4 60 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Listing 12- 40. Handling the Mouse Events with the Search Suggestions. Listing 12- 38 fixes this issue. CHAPTER 12 ■ IMPLEMENTING SITE SEARCH 4 59 90 6 3Ch12CMP3 11/13 /07 9 :26 PM Page 4 59 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Listing 12- 38.

Ngày đăng: 12/08/2014, 13:21

TỪ KHÓA LIÊN QUAN