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