001/* 002 * (C) Copyright 2014 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Thomas Roger 018 */ 019 020package org.nuxeo.search.ui.seam; 021 022import static org.apache.commons.lang.StringUtils.isNotBlank; 023import static org.apache.commons.logging.LogFactory.getLog; 024import static org.jboss.seam.ScopeType.CONVERSATION; 025import static org.jboss.seam.annotations.Install.FRAMEWORK; 026import static org.nuxeo.ecm.webapp.helpers.EventNames.LOCAL_CONFIGURATION_CHANGED; 027import static org.nuxeo.ecm.webapp.helpers.EventNames.USER_ALL_DOCUMENT_TYPES_SELECTION_CHANGED; 028 029import java.io.Serializable; 030import java.io.UnsupportedEncodingException; 031import java.util.ArrayList; 032import java.util.List; 033import java.util.Map; 034 035import javax.faces.application.FacesMessage; 036import javax.faces.component.UIComponent; 037import javax.faces.component.UIViewRoot; 038import javax.faces.context.FacesContext; 039import javax.faces.model.SelectItem; 040import javax.faces.model.SelectItemGroup; 041import javax.faces.validator.ValidatorException; 042 043import org.apache.commons.lang.StringUtils; 044import org.apache.commons.logging.Log; 045import org.jboss.seam.annotations.Begin; 046import org.jboss.seam.annotations.In; 047import org.jboss.seam.annotations.Install; 048import org.jboss.seam.annotations.Name; 049import org.jboss.seam.annotations.Observer; 050import org.jboss.seam.annotations.Scope; 051import org.jboss.seam.annotations.intercept.BypassInterceptors; 052import org.jboss.seam.core.Events; 053import org.jboss.seam.faces.FacesMessages; 054import org.jboss.seam.international.StatusMessage; 055import org.nuxeo.ecm.core.api.CoreSession; 056import org.nuxeo.ecm.core.api.DocumentModel; 057import org.nuxeo.ecm.core.api.IdRef; 058import org.nuxeo.ecm.core.api.PathRef; 059import org.nuxeo.ecm.core.api.impl.DocumentLocationImpl; 060import org.nuxeo.ecm.platform.contentview.jsf.ContentView; 061import org.nuxeo.ecm.platform.contentview.jsf.ContentViewHeader; 062import org.nuxeo.ecm.platform.contentview.jsf.ContentViewService; 063import org.nuxeo.ecm.platform.contentview.jsf.ContentViewState; 064import org.nuxeo.ecm.platform.contentview.jsf.ContentViewStateImpl; 065import org.nuxeo.ecm.platform.contentview.json.JSONContentViewState; 066import org.nuxeo.ecm.platform.contentview.seam.ContentViewActions; 067import org.nuxeo.ecm.platform.ui.web.api.NavigationContext; 068import org.nuxeo.ecm.platform.ui.web.api.WebActions; 069import org.nuxeo.ecm.platform.ui.web.rest.RestHelper; 070import org.nuxeo.ecm.platform.ui.web.util.BaseURL; 071import org.nuxeo.ecm.platform.ui.web.util.ComponentUtils; 072import org.nuxeo.ecm.platform.url.DocumentViewImpl; 073import org.nuxeo.ecm.platform.url.api.DocumentView; 074import org.nuxeo.ecm.platform.url.api.DocumentViewCodecManager; 075import org.nuxeo.ecm.webapp.action.ActionContextProvider; 076import org.nuxeo.ecm.webapp.documentsLists.DocumentsListsManager; 077import org.nuxeo.ecm.webapp.helpers.EventNames; 078import org.nuxeo.runtime.api.Framework; 079import org.nuxeo.search.ui.SearchUIService; 080 081/** 082 * Seam bean handling Search main tab actions. 083 * 084 * @since 6.0 085 */ 086@Name("searchUIActions") 087@Scope(CONVERSATION) 088@Install(precedence = FRAMEWORK) 089public class SearchUIActions implements Serializable { 090 091 private static final long serialVersionUID = 1L; 092 093 private static final Log log = getLog(SearchUIActions.class); 094 095 public static final String SAVED_SEARCHES_LABEL = "label.saved.searches"; 096 097 public static final String SHARED_SEARCHES_LABEL = "label.shared.searches"; 098 099 public static final String SEARCH_FILTERS_LABEL = "label.search.filters"; 100 101 public static final String SEARCH_SAVED_LABEL = "label.search.saved"; 102 103 public static final String MAIN_TABS_SEARCH = "MAIN_TABS:search"; 104 105 public static final String SEARCH_VIEW_ID = "/search/search.xhtml"; 106 107 public static final String SEARCH_CODEC = "docpathsearch"; 108 109 public static final String SIMPLE_SEARCH_CONTENT_VIEW_NAME = "simple_search"; 110 111 public static final String NXQL_SEARCH_CONTENT_VIEW_NAME = "nxql_search"; 112 113 public static final String DEFAULT_NXQL_QUERY = "SELECT * FROM Document" 114 + " WHERE ecm:mixinType != 'HiddenInNavigation'" + " AND ecm:isProxy = 0 AND ecm:isCheckedInVersion = 0" 115 + " AND ecm:currentLifeCycleState != 'deleted'"; 116 117 public static final String CONTENT_VIEW_NAME_PARAMETER = "contentViewName"; 118 119 public static final String CURRENT_PAGE_PARAMETER = "currentPage"; 120 121 public static final String PAGE_SIZE_PARAMETER = "pageSize"; 122 123 public static final String CONTENT_VIEW_STATE_PARAMETER = "state"; 124 125 public static final String SEARCH_TERM_PARAMETER = "searchTerm"; 126 127 /** 128 * Event name for search selection change, raised with selected corresponding content view name. 129 * 130 * @since 8.1 131 */ 132 public static final String SEARCH_SELECTED_EVENT = "searchSelected"; 133 134 /** 135 * Event name for search selection change, raised with saved document model. 136 * 137 * @since 8.1 138 */ 139 public static final String SEARCH_SAVED_EVENT = "searchSaved"; 140 141 @In(create = true) 142 protected transient NavigationContext navigationContext; 143 144 @In(create = true, required = false) 145 protected transient CoreSession documentManager; 146 147 @In(create = true, required = false) 148 protected transient ActionContextProvider actionContextProvider; 149 150 @In(create = true) 151 protected transient WebActions webActions; 152 153 @In(create = true) 154 protected RestHelper restHelper; 155 156 @In(create = true) 157 protected ContentViewActions contentViewActions; 158 159 @In(create = true) 160 protected ContentViewService contentViewService; 161 162 @In(create = true) 163 protected DocumentsListsManager documentsListsManager; 164 165 @In(create = true, required = false) 166 protected FacesMessages facesMessages; 167 168 @In(create = true) 169 protected Map<String, String> messages; 170 171 protected String simpleSearchKeywords = ""; 172 173 protected String nxqlQuery = DEFAULT_NXQL_QUERY; 174 175 protected List<ContentViewHeader> contentViewHeaders; 176 177 protected String currentContentViewName; 178 179 protected String currentSelectedSavedSearchId; 180 181 protected String currentPage; 182 183 protected String pageSize; 184 185 protected String searchTerm; 186 187 protected String savedSearchTitle; 188 189 public String getSearchMainTab() { 190 return MAIN_TABS_SEARCH; 191 } 192 193 public void setSearchMainTab(String tabs) { 194 webActions.setCurrentTabIds(!StringUtils.isBlank(tabs) ? tabs : MAIN_TABS_SEARCH); 195 } 196 197 public String getSearchViewTitle() { 198 if (currentSelectedSavedSearchId != null) { 199 DocumentModel savedSearch = documentManager.getDocument(new IdRef(currentSelectedSavedSearchId)); 200 return savedSearch.getTitle(); 201 } else if (currentContentViewName != null) { 202 ContentView cv = contentViewActions.getContentView(currentContentViewName); 203 String title = cv.getTranslateTitle() ? messages.get(cv.getTitle()) : cv.getTitle(); 204 return isNotBlank(title) ? title : currentContentViewName; 205 } 206 return null; 207 } 208 209 /** 210 * Returns true if the user is viewing SEARCH. 211 */ 212 public boolean isOnSearchView() { 213 if (FacesContext.getCurrentInstance() == null) { 214 return false; 215 } 216 217 UIViewRoot viewRoot = FacesContext.getCurrentInstance().getViewRoot(); 218 if (viewRoot != null) { 219 String viewId = viewRoot.getViewId(); 220 // FIXME find a better way to update the current document only 221 // if we are on SEARCH 222 if (SEARCH_VIEW_ID.equals(viewId)) { 223 return true; 224 } 225 } 226 return false; 227 } 228 229 public String getJSONContentViewState() throws UnsupportedEncodingException { 230 ContentView contentView = contentViewActions.getContentView(currentContentViewName); 231 ContentViewService contentViewService = Framework.getService(ContentViewService.class); 232 ContentViewState state = contentViewService.saveContentView(contentView); 233 return JSONContentViewState.toJSON(state, true); 234 } 235 236 public String getCurrentContentViewName() { 237 if (currentContentViewName == null) { 238 List<ContentViewHeader> contentViewHeaders = getContentViewHeaders(); 239 if (!contentViewHeaders.isEmpty()) { 240 currentContentViewName = contentViewHeaders.get(0).getName(); 241 } 242 } 243 return currentContentViewName; 244 } 245 246 public void setCurrentContentViewName(String contentViewName) { 247 this.currentContentViewName = contentViewName; 248 } 249 250 public String getCurrentSelectedSavedSearchId() { 251 return currentSelectedSavedSearchId != null ? currentSelectedSavedSearchId : currentContentViewName; 252 } 253 254 public void setCurrentSelectedSavedSearchId(String selectedSavedSearchId) throws UnsupportedEncodingException { 255 resetCurrentContentViewWorkingList(); 256 257 for (ContentViewHeader contentViewHeader : contentViewHeaders) { 258 if (contentViewHeader.getName().equals(selectedSavedSearchId)) { 259 contentViewActions.reset(currentContentViewName); 260 currentContentViewName = selectedSavedSearchId; 261 Events.instance().raiseEvent(SEARCH_SELECTED_EVENT, currentContentViewName); 262 currentSelectedSavedSearchId = null; 263 return; 264 } 265 } 266 DocumentModel savedSearch = documentManager.getDocument(new IdRef(selectedSavedSearchId)); 267 loadSavedSearch(savedSearch); 268 } 269 270 protected void resetCurrentContentViewWorkingList() { 271 if (currentContentViewName != null) { 272 ContentView contentView = contentViewActions.getContentView(currentContentViewName); 273 if (contentView != null) { 274 documentsListsManager.resetWorkingList(contentView.getSelectionListName()); 275 } 276 } 277 } 278 279 public void loadSavedSearch(DocumentModel searchDocument) throws UnsupportedEncodingException { 280 SearchUIService searchUIService = Framework.getService(SearchUIService.class); 281 ContentViewState contentViewState = searchUIService.loadSearch(searchDocument); 282 if (contentViewState != null) { 283 ContentView contentView = contentViewActions.restoreContentView(contentViewState); 284 currentContentViewName = contentView.getName(); 285 Events.instance().raiseEvent(SEARCH_SELECTED_EVENT, currentContentViewName); 286 } 287 currentSelectedSavedSearchId = searchDocument.getId(); 288 } 289 290 public List<ContentViewHeader> getContentViewHeaders() { 291 if (contentViewHeaders == null) { 292 SearchUIService searchUIService = Framework.getService(SearchUIService.class); 293 contentViewHeaders = searchUIService.getContentViewHeaders(actionContextProvider.createActionContext(), 294 navigationContext.getCurrentDocument()); 295 } 296 return contentViewHeaders; 297 } 298 299 public void clearSearch() { 300 if (currentContentViewName != null) { 301 contentViewActions.reset(currentContentViewName); 302 resetCurrentContentViewWorkingList(); 303 } 304 } 305 306 public void refreshAndRewind() { 307 String contentViewName = getCurrentContentViewName(); 308 if (contentViewName != null) { 309 contentViewActions.refreshAndRewind(contentViewName); 310 resetCurrentContentViewWorkingList(); 311 } 312 } 313 314 public void refreshAndRewindAndResetAggregates() { 315 contentViewActions.resetAggregates(getCurrentContentViewName()); 316 refreshAndRewind(); 317 } 318 319 /* 320 * ----- Load / Save searches ----- 321 */ 322 323 public List<SelectItem> getAllSavedSearchesSelectItems() { 324 List<SelectItem> items = new ArrayList<>(); 325 326 // Add flagged content views 327 SelectItemGroup flaggedGroup = new SelectItemGroup(messages.get(SEARCH_FILTERS_LABEL)); 328 List<ContentViewHeader> flaggedSavedSearches = getContentViewHeaders(); 329 List<SelectItem> flaggedSavedSearchesItems = convertCVToSelectItems(flaggedSavedSearches); 330 flaggedGroup.setSelectItems( 331 flaggedSavedSearchesItems.toArray(new SelectItem[flaggedSavedSearchesItems.size()])); 332 items.add(flaggedGroup); 333 334 // Add saved searches 335 List<DocumentModel> userSavedSearches = getSavedSearches(); 336 if (!userSavedSearches.isEmpty()) { 337 SelectItemGroup userGroup = new SelectItemGroup(messages.get(SAVED_SEARCHES_LABEL)); 338 339 List<SelectItem> userSavedSearchesItems = convertToSelectItems(userSavedSearches); 340 userGroup.setSelectItems(userSavedSearchesItems.toArray(new SelectItem[userSavedSearchesItems.size()])); 341 items.add(userGroup); 342 } 343 344 // Add shared searches 345 List<DocumentModel> otherUsersSavedFacetedSearches = getSharedSearches(); 346 if (!otherUsersSavedFacetedSearches.isEmpty()) { 347 List<SelectItem> otherUsersSavedSearchesItems = convertToSelectItems(otherUsersSavedFacetedSearches); 348 SelectItemGroup allGroup = new SelectItemGroup(messages.get(SHARED_SEARCHES_LABEL)); 349 allGroup.setSelectItems( 350 otherUsersSavedSearchesItems.toArray(new SelectItem[otherUsersSavedSearchesItems.size()])); 351 items.add(allGroup); 352 } 353 return items; 354 } 355 356 protected List<DocumentModel> getSavedSearches() { 357 SearchUIService searchUIService = Framework.getService(SearchUIService.class); 358 return searchUIService.getCurrentUserSavedSearches(documentManager); 359 } 360 361 protected List<DocumentModel> getSharedSearches() { 362 SearchUIService searchUIService = Framework.getService(SearchUIService.class); 363 return searchUIService.getSharedSavedSearches(documentManager); 364 } 365 366 protected List<SelectItem> convertToSelectItems(List<DocumentModel> docs) { 367 List<SelectItem> items = new ArrayList<>(); 368 for (DocumentModel doc : docs) { 369 items.add(new SelectItem(doc.getId(), doc.getTitle(), "")); 370 } 371 return items; 372 } 373 374 protected List<SelectItem> convertCVToSelectItems(List<ContentViewHeader> contentViewHeaders) { 375 List<SelectItem> items = new ArrayList<>(); 376 for (ContentViewHeader contentViewHeader : contentViewHeaders) { 377 items.add(new SelectItem(contentViewHeader.getName(), messages.get(contentViewHeader.getTitle()), "")); 378 } 379 return items; 380 } 381 382 public String getSavedSearchTitle() { 383 return savedSearchTitle; 384 } 385 386 public void setSavedSearchTitle(String savedSearchTitle) { 387 this.savedSearchTitle = savedSearchTitle; 388 } 389 390 public String saveSearch() { 391 ContentView contentView = contentViewActions.getContentView(getCurrentContentViewName()); 392 if (contentView != null) { 393 ContentViewState state = contentViewService.saveContentView(contentView); 394 SearchUIService searchUIService = Framework.getService(SearchUIService.class); 395 DocumentModel savedSearch = searchUIService.saveSearch(documentManager, state, savedSearchTitle); 396 currentSelectedSavedSearchId = savedSearch.getId(); 397 398 Events.instance().raiseEvent(SEARCH_SAVED_EVENT, savedSearch); 399 400 savedSearchTitle = null; 401 facesMessages.add(StatusMessage.Severity.INFO, messages.get(SEARCH_SAVED_LABEL)); 402 } 403 return null; 404 } 405 406 /** 407 * Retsurns true if current search can be saved. 408 * <p> 409 * Returns false if current content view is waiting for a first execution. 410 * 411 * @since 7.4 412 */ 413 public boolean getCanSaveSearch() { 414 ContentView contentView = contentViewActions.getContentView(getCurrentContentViewName()); 415 if (contentView != null) { 416 boolean res = !contentView.isWaitForExecution() || contentView.isExecuted(); 417 return res; 418 } 419 return false; 420 } 421 422 public void cancelSaveSearch() { 423 savedSearchTitle = null; 424 } 425 426 /* 427 * ----- Permanent links ----- 428 */ 429 430 public void setState(String state) throws UnsupportedEncodingException { 431 if (isNotBlank(state)) { 432 Long finalPageSize = null; 433 if (!StringUtils.isBlank(pageSize)) { 434 try { 435 finalPageSize = Long.valueOf(pageSize); 436 } catch (NumberFormatException e) { 437 log.warn(String.format("Unable to parse '%s' parameter with value '%s'", PAGE_SIZE_PARAMETER, 438 pageSize)); 439 } 440 } 441 442 Long finalCurrentPage = null; 443 if (!StringUtils.isBlank(currentPage)) { 444 try { 445 finalCurrentPage = Long.valueOf(currentPage); 446 } catch (NumberFormatException e) { 447 log.warn(String.format("Unable to parse '%s' parameter with value '%s'", CURRENT_PAGE_PARAMETER, 448 currentPage)); 449 } 450 } 451 452 String cvName = getCurrentContentViewName(); 453 List<ContentViewHeader> contentViewHeaders = getContentViewHeaders(); 454 if (cvName != null && contentViewHeaders != null) { 455 boolean canRestore = false; 456 for (ContentViewHeader contentViewHeader : getContentViewHeaders()) { 457 if (cvName.equals(contentViewHeader.getName())) { 458 canRestore = true; 459 } 460 } 461 462 if (canRestore) { 463 contentViewActions.restoreContentView(getCurrentContentViewName(), finalCurrentPage, finalPageSize, 464 null, state); 465 } else { 466 invalidateContentViewsName(); 467 } 468 } 469 } 470 } 471 472 public String getCurrentPage() { 473 return currentPage; 474 } 475 476 public void setCurrentPage(String currentPage) { 477 this.currentPage = currentPage; 478 } 479 480 public String getPageSize() { 481 return pageSize; 482 } 483 484 public void setPageSize(String pageSize) { 485 this.pageSize = pageSize; 486 } 487 488 public void setSearchTerm(String searchTerm) throws UnsupportedEncodingException { 489 // If the search term is not defined, we don't do the logic 490 if (!StringUtils.isEmpty(searchTerm)) { 491 // By default, the "simple_search" content view is used 492 currentContentViewName = SIMPLE_SEARCH_CONTENT_VIEW_NAME; 493 // Create a ContentViewState 494 ContentView cv = contentViewService.getContentView(SIMPLE_SEARCH_CONTENT_VIEW_NAME); 495 DocumentModel searchDocumentModel = cv.getSearchDocumentModel(); 496 // set the search term 497 searchDocumentModel.setPropertyValue("default_search:ecm_fulltext", searchTerm); 498 ContentViewState state = new ContentViewStateImpl(); 499 state.setSearchDocumentModel(searchDocumentModel); 500 state.setContentViewName(getCurrentContentViewName()); 501 ContentView ccv = contentViewActions.restoreContentView(state); 502 ccv.setExecuted(true); 503 } 504 } 505 506 /** 507 * Compute a permanent link for the current search. 508 */ 509 public String getSearchPermanentLinkUrl() throws UnsupportedEncodingException { 510 // do not try to compute an URL if we don't have any CoreSession 511 if (documentManager == null) { 512 return null; 513 } 514 515 return generateSearchUrl(true); 516 } 517 518 /** 519 * @return the URL of the search tab with the search term defined. 520 */ 521 public String getSearchTabUrl(String searchTerm) throws UnsupportedEncodingException { 522 // do not try to compute an URL if we don't have any CoreSession 523 if (documentManager == null) { 524 return null; 525 } 526 // Set the value of the searched term 527 this.searchTerm = searchTerm; 528 529 return generateSearchUrl(false); 530 } 531 532 /** 533 * Create the url to access the Search tab. 534 * 535 * @param withState If set to true, the state is added in the parameters. 536 */ 537 protected String generateSearchUrl(boolean withState) throws UnsupportedEncodingException { 538 String currentContentViewName = getCurrentContentViewName(); 539 DocumentModel currentDocument = navigationContext.getCurrentDocument(); 540 DocumentView docView = computeDocumentView(currentDocument); 541 docView.setViewId("search"); 542 docView.addParameter(CONTENT_VIEW_NAME_PARAMETER, currentContentViewName); 543 // Add the state if needed 544 if (withState) { 545 docView.addParameter(CONTENT_VIEW_STATE_PARAMETER, getJSONContentViewState()); 546 } 547 548 DocumentViewCodecManager documentViewCodecManager = Framework.getService(DocumentViewCodecManager.class); 549 String url = documentViewCodecManager.getUrlFromDocumentView(SEARCH_CODEC, docView, true, BaseURL.getBaseURL()); 550 551 return RestHelper.addCurrentConversationParameters(url); 552 } 553 554 protected DocumentView computeDocumentView(DocumentModel doc) { 555 return new DocumentViewImpl(new DocumentLocationImpl(documentManager.getRepositoryName(), 556 doc != null ? new PathRef(doc.getPathAsString()) : null)); 557 } 558 559 /* 560 * ----- Simple Search ----- 561 */ 562 public String getSimpleSearchKeywords() { 563 return simpleSearchKeywords; 564 } 565 566 public void setSimpleSearchKeywords(String simpleSearchKeywords) { 567 this.simpleSearchKeywords = simpleSearchKeywords; 568 } 569 570 public void validateSimpleSearchKeywords(FacesContext context, UIComponent component, Object value) { 571 if (!(value instanceof String) || StringUtils.isEmpty(((String) value).trim())) { 572 FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, 573 ComponentUtils.translate(context, "feedback.search.noKeywords"), null); 574 // also add global message 575 context.addMessage(null, message); 576 throw new ValidatorException(message); 577 } 578 String[] keywords = ((String) value).trim().split(" "); 579 for (String keyword : keywords) { 580 if (keyword.startsWith("*")) { 581 // Can't begin search with * character 582 FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, 583 ComponentUtils.translate(context, "feedback.search.star"), null); 584 // also add global message 585 context.addMessage(null, message); 586 throw new ValidatorException(message); 587 } 588 } 589 } 590 591 public String doSimpleSearch() { 592 setSearchMainTab(null); 593 currentContentViewName = SIMPLE_SEARCH_CONTENT_VIEW_NAME; 594 ContentView contentView = contentViewActions.getContentView(SIMPLE_SEARCH_CONTENT_VIEW_NAME); 595 DocumentModel searchDoc = contentView.getSearchDocumentModel(); 596 searchDoc.setPropertyValue("defaults:ecm_fulltext", simpleSearchKeywords); 597 refreshAndRewind(); 598 return "search"; 599 } 600 601 /* 602 * ----- NXQL Search ----- 603 */ 604 public String getNxqlQuery() { 605 return nxqlQuery; 606 } 607 608 public void setNxqlQuery(String nxqlQuery) { 609 this.nxqlQuery = nxqlQuery; 610 } 611 612 public boolean isNxqlSearchSelected() { 613 return NXQL_SEARCH_CONTENT_VIEW_NAME.equals(currentContentViewName); 614 } 615 616 @Begin(id = "#{conversationIdGenerator.currentOrNewMainConversationId}", join = true) 617 public String loadPermanentLink(DocumentView docView) { 618 restHelper.initContextFromRestRequest(docView); 619 return "search"; 620 } 621 622 @Observer(value = LOCAL_CONFIGURATION_CHANGED) 623 public void invalidateContentViewsName() { 624 clearSearch(); 625 contentViewHeaders = null; 626 currentContentViewName = null; 627 } 628 629 @Observer(value = USER_ALL_DOCUMENT_TYPES_SELECTION_CHANGED) 630 public void invalidateContentViewsNameIfChanged() { 631 List<ContentViewHeader> temp = new ArrayList<>( 632 Framework.getService(SearchUIService.class).getContentViewHeaders( 633 actionContextProvider.createActionContext(), navigationContext.getCurrentDocument())); 634 if (temp != null) { 635 if (!temp.equals(contentViewHeaders)) { 636 invalidateContentViewsName(); 637 } 638 if (!temp.isEmpty()) { 639 String s = temp.get(0).getName(); 640 if (s != null && !s.equals(currentContentViewName)) { 641 invalidateContentViewsName(); 642 } 643 } 644 } 645 } 646 647 /** 648 * Reset attributes. 649 */ 650 @Observer(value = { EventNames.FLUSH_EVENT }, create = false) 651 @BypassInterceptors 652 public void resetOnFlush() { 653 contentViewHeaders = null; 654 currentSelectedSavedSearchId = null; 655 currentContentViewName = null; 656 nxqlQuery = DEFAULT_NXQL_QUERY; 657 simpleSearchKeywords = ""; 658 } 659 660 public String getSearchTermParameter() { 661 return SEARCH_TERM_PARAMETER; 662 } 663 664 /** 665 * Triggers content view refresh/reset on saved search. 666 * 667 * @since 8.1 668 */ 669 @Observer(value = { SEARCH_SAVED_EVENT }) 670 public void onSearchSaved() { 671 contentViewActions.refreshOnSeamEvent(SEARCH_SAVED_EVENT); 672 contentViewActions.resetPageProviderOnSeamEvent(SEARCH_SAVED_EVENT); 673 } 674 675}