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 documentsListsManager.resetWorkingList(contentView.getSelectionListName()); 274 } 275 } 276 277 public void loadSavedSearch(DocumentModel searchDocument) throws UnsupportedEncodingException { 278 SearchUIService searchUIService = Framework.getService(SearchUIService.class); 279 ContentViewState contentViewState = searchUIService.loadSearch(searchDocument); 280 if (contentViewState != null) { 281 ContentView contentView = contentViewActions.restoreContentView(contentViewState); 282 currentContentViewName = contentView.getName(); 283 Events.instance().raiseEvent(SEARCH_SELECTED_EVENT, currentContentViewName); 284 } 285 currentSelectedSavedSearchId = searchDocument.getId(); 286 } 287 288 public List<ContentViewHeader> getContentViewHeaders() { 289 if (contentViewHeaders == null) { 290 SearchUIService searchUIService = Framework.getService(SearchUIService.class); 291 contentViewHeaders = searchUIService.getContentViewHeaders(actionContextProvider.createActionContext(), 292 navigationContext.getCurrentDocument()); 293 } 294 return contentViewHeaders; 295 } 296 297 public void clearSearch() { 298 if (currentContentViewName != null) { 299 contentViewActions.reset(currentContentViewName); 300 resetCurrentContentViewWorkingList(); 301 } 302 } 303 304 public void refreshAndRewind() { 305 String contentViewName = getCurrentContentViewName(); 306 if (contentViewName != null) { 307 contentViewActions.refreshAndRewind(contentViewName); 308 resetCurrentContentViewWorkingList(); 309 } 310 } 311 312 public void refreshAndRewindAndResetAggregates() { 313 contentViewActions.resetAggregates(getCurrentContentViewName()); 314 refreshAndRewind(); 315 } 316 317 /* 318 * ----- Load / Save searches ----- 319 */ 320 321 public List<SelectItem> getAllSavedSearchesSelectItems() { 322 List<SelectItem> items = new ArrayList<>(); 323 324 // Add flagged content views 325 SelectItemGroup flaggedGroup = new SelectItemGroup(messages.get(SEARCH_FILTERS_LABEL)); 326 List<ContentViewHeader> flaggedSavedSearches = getContentViewHeaders(); 327 List<SelectItem> flaggedSavedSearchesItems = convertCVToSelectItems(flaggedSavedSearches); 328 flaggedGroup.setSelectItems(flaggedSavedSearchesItems.toArray(new SelectItem[flaggedSavedSearchesItems.size()])); 329 items.add(flaggedGroup); 330 331 // Add saved searches 332 List<DocumentModel> userSavedSearches = getSavedSearches(); 333 if (!userSavedSearches.isEmpty()) { 334 SelectItemGroup userGroup = new SelectItemGroup(messages.get(SAVED_SEARCHES_LABEL)); 335 336 List<SelectItem> userSavedSearchesItems = convertToSelectItems(userSavedSearches); 337 userGroup.setSelectItems(userSavedSearchesItems.toArray(new SelectItem[userSavedSearchesItems.size()])); 338 items.add(userGroup); 339 } 340 341 // Add shared searches 342 List<DocumentModel> otherUsersSavedFacetedSearches = getSharedSearches(); 343 if (!otherUsersSavedFacetedSearches.isEmpty()) { 344 List<SelectItem> otherUsersSavedSearchesItems = convertToSelectItems(otherUsersSavedFacetedSearches); 345 SelectItemGroup allGroup = new SelectItemGroup(messages.get(SHARED_SEARCHES_LABEL)); 346 allGroup.setSelectItems(otherUsersSavedSearchesItems.toArray(new SelectItem[otherUsersSavedSearchesItems.size()])); 347 items.add(allGroup); 348 } 349 return items; 350 } 351 352 protected List<DocumentModel> getSavedSearches() { 353 SearchUIService searchUIService = Framework.getService(SearchUIService.class); 354 return searchUIService.getCurrentUserSavedSearches(documentManager); 355 } 356 357 protected List<DocumentModel> getSharedSearches() { 358 SearchUIService searchUIService = Framework.getService(SearchUIService.class); 359 return searchUIService.getSharedSavedSearches(documentManager); 360 } 361 362 protected List<SelectItem> convertToSelectItems(List<DocumentModel> docs) { 363 List<SelectItem> items = new ArrayList<>(); 364 for (DocumentModel doc : docs) { 365 items.add(new SelectItem(doc.getId(), doc.getTitle(), "")); 366 } 367 return items; 368 } 369 370 protected List<SelectItem> convertCVToSelectItems(List<ContentViewHeader> contentViewHeaders) { 371 List<SelectItem> items = new ArrayList<>(); 372 for (ContentViewHeader contentViewHeader : contentViewHeaders) { 373 items.add(new SelectItem(contentViewHeader.getName(), messages.get(contentViewHeader.getTitle()), "")); 374 } 375 return items; 376 } 377 378 public String getSavedSearchTitle() { 379 return savedSearchTitle; 380 } 381 382 public void setSavedSearchTitle(String savedSearchTitle) { 383 this.savedSearchTitle = savedSearchTitle; 384 } 385 386 public String saveSearch() { 387 ContentView contentView = contentViewActions.getContentView(getCurrentContentViewName()); 388 if (contentView != null) { 389 ContentViewState state = contentViewService.saveContentView(contentView); 390 SearchUIService searchUIService = Framework.getService(SearchUIService.class); 391 DocumentModel savedSearch = searchUIService.saveSearch(documentManager, state, savedSearchTitle); 392 currentSelectedSavedSearchId = savedSearch.getId(); 393 394 Events.instance().raiseEvent(SEARCH_SAVED_EVENT, savedSearch); 395 396 savedSearchTitle = null; 397 facesMessages.add(StatusMessage.Severity.INFO, messages.get(SEARCH_SAVED_LABEL)); 398 } 399 return null; 400 } 401 402 /** 403 * Retsurns true if current search can be saved. 404 * <p> 405 * Returns false if current content view is waiting for a first execution. 406 * 407 * @since 7.4 408 */ 409 public boolean getCanSaveSearch() { 410 ContentView contentView = contentViewActions.getContentView(getCurrentContentViewName()); 411 if (contentView != null) { 412 boolean res = !contentView.isWaitForExecution() || contentView.isExecuted(); 413 return res; 414 } 415 return false; 416 } 417 418 public void cancelSaveSearch() { 419 savedSearchTitle = null; 420 } 421 422 /* 423 * ----- Permanent links ----- 424 */ 425 426 public void setState(String state) throws UnsupportedEncodingException { 427 if (isNotBlank(state)) { 428 Long finalPageSize = null; 429 if (!StringUtils.isBlank(pageSize)) { 430 try { 431 finalPageSize = Long.valueOf(pageSize); 432 } catch (NumberFormatException e) { 433 log.warn(String.format("Unable to parse '%s' parameter with value '%s'", PAGE_SIZE_PARAMETER, 434 pageSize)); 435 } 436 } 437 438 Long finalCurrentPage = null; 439 if (!StringUtils.isBlank(currentPage)) { 440 try { 441 finalCurrentPage = Long.valueOf(currentPage); 442 } catch (NumberFormatException e) { 443 log.warn(String.format("Unable to parse '%s' parameter with value '%s'", CURRENT_PAGE_PARAMETER, 444 currentPage)); 445 } 446 } 447 448 String cvName = getCurrentContentViewName(); 449 List<ContentViewHeader> contentViewHeaders = getContentViewHeaders(); 450 if (cvName != null && contentViewHeaders != null) { 451 boolean canRestore = false; 452 for (ContentViewHeader contentViewHeader : getContentViewHeaders()) { 453 if (cvName.equals(contentViewHeader.getName())) { 454 canRestore = true; 455 } 456 } 457 458 if (canRestore) { 459 contentViewActions.restoreContentView(getCurrentContentViewName(), finalCurrentPage, finalPageSize, 460 null, state); 461 } else { 462 invalidateContentViewsName(); 463 } 464 } 465 } 466 } 467 468 public String getCurrentPage() { 469 return currentPage; 470 } 471 472 public void setCurrentPage(String currentPage) { 473 this.currentPage = currentPage; 474 } 475 476 public String getPageSize() { 477 return pageSize; 478 } 479 480 public void setPageSize(String pageSize) { 481 this.pageSize = pageSize; 482 } 483 484 public void setSearchTerm(String searchTerm) throws UnsupportedEncodingException { 485 // If the search term is not defined, we don't do the logic 486 if (!StringUtils.isEmpty(searchTerm)) { 487 // By default, the "simple_search" content view is used 488 currentContentViewName = SIMPLE_SEARCH_CONTENT_VIEW_NAME; 489 // Create a ContentViewState 490 ContentView cv = contentViewService.getContentView(SIMPLE_SEARCH_CONTENT_VIEW_NAME); 491 DocumentModel searchDocumentModel = cv.getSearchDocumentModel(); 492 // set the search term 493 searchDocumentModel.setPropertyValue("default_search:ecm_fulltext", searchTerm); 494 ContentViewState state = new ContentViewStateImpl(); 495 state.setSearchDocumentModel(searchDocumentModel); 496 state.setContentViewName(getCurrentContentViewName()); 497 ContentView ccv = contentViewActions.restoreContentView(state); 498 ccv.setExecuted(true); 499 } 500 } 501 502 /** 503 * Compute a permanent link for the current search. 504 */ 505 public String getSearchPermanentLinkUrl() throws UnsupportedEncodingException { 506 // do not try to compute an URL if we don't have any CoreSession 507 if (documentManager == null) { 508 return null; 509 } 510 511 return generateSearchUrl(true); 512 } 513 514 /** 515 * @return the URL of the search tab with the search term defined. 516 */ 517 public String getSearchTabUrl(String searchTerm) throws UnsupportedEncodingException { 518 // do not try to compute an URL if we don't have any CoreSession 519 if (documentManager == null) { 520 return null; 521 } 522 // Set the value of the searched term 523 this.searchTerm = searchTerm; 524 525 return generateSearchUrl(false); 526 } 527 528 /** 529 * Create the url to access the Search tab. 530 * 531 * @param withState If set to true, the state is added in the parameters. 532 */ 533 protected String generateSearchUrl(boolean withState) throws UnsupportedEncodingException { 534 String currentContentViewName = getCurrentContentViewName(); 535 DocumentModel currentDocument = navigationContext.getCurrentDocument(); 536 DocumentView docView = computeDocumentView(currentDocument); 537 docView.setViewId("search"); 538 docView.addParameter(CONTENT_VIEW_NAME_PARAMETER, currentContentViewName); 539 // Add the state if needed 540 if (withState) { 541 docView.addParameter(CONTENT_VIEW_STATE_PARAMETER, getJSONContentViewState()); 542 } 543 544 DocumentViewCodecManager documentViewCodecManager = Framework.getService(DocumentViewCodecManager.class); 545 String url = documentViewCodecManager.getUrlFromDocumentView(SEARCH_CODEC, docView, true, BaseURL.getBaseURL()); 546 547 return RestHelper.addCurrentConversationParameters(url); 548 } 549 550 protected DocumentView computeDocumentView(DocumentModel doc) { 551 return new DocumentViewImpl(new DocumentLocationImpl(documentManager.getRepositoryName(), 552 doc != null ? new PathRef(doc.getPathAsString()) : null)); 553 } 554 555 /* 556 * ----- Simple Search ----- 557 */ 558 public String getSimpleSearchKeywords() { 559 return simpleSearchKeywords; 560 } 561 562 public void setSimpleSearchKeywords(String simpleSearchKeywords) { 563 this.simpleSearchKeywords = simpleSearchKeywords; 564 } 565 566 public void validateSimpleSearchKeywords(FacesContext context, UIComponent component, Object value) { 567 if (!(value instanceof String) || StringUtils.isEmpty(((String) value).trim())) { 568 FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, ComponentUtils.translate(context, 569 "feedback.search.noKeywords"), null); 570 // also add global message 571 context.addMessage(null, message); 572 throw new ValidatorException(message); 573 } 574 String[] keywords = ((String) value).trim().split(" "); 575 for (String keyword : keywords) { 576 if (keyword.startsWith("*")) { 577 // Can't begin search with * character 578 FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, ComponentUtils.translate(context, 579 "feedback.search.star"), null); 580 // also add global message 581 context.addMessage(null, message); 582 throw new ValidatorException(message); 583 } 584 } 585 } 586 587 public String doSimpleSearch() { 588 setSearchMainTab(null); 589 currentContentViewName = SIMPLE_SEARCH_CONTENT_VIEW_NAME; 590 ContentView contentView = contentViewActions.getContentView(SIMPLE_SEARCH_CONTENT_VIEW_NAME); 591 DocumentModel searchDoc = contentView.getSearchDocumentModel(); 592 searchDoc.setPropertyValue("defaults:ecm_fulltext", simpleSearchKeywords); 593 refreshAndRewind(); 594 return "search"; 595 } 596 597 /* 598 * ----- NXQL Search ----- 599 */ 600 public String getNxqlQuery() { 601 return nxqlQuery; 602 } 603 604 public void setNxqlQuery(String nxqlQuery) { 605 this.nxqlQuery = nxqlQuery; 606 } 607 608 public boolean isNxqlSearchSelected() { 609 return NXQL_SEARCH_CONTENT_VIEW_NAME.equals(currentContentViewName); 610 } 611 612 @Begin(id = "#{conversationIdGenerator.currentOrNewMainConversationId}", join = true) 613 public String loadPermanentLink(DocumentView docView) { 614 restHelper.initContextFromRestRequest(docView); 615 return "search"; 616 } 617 618 @Observer(value = LOCAL_CONFIGURATION_CHANGED) 619 public void invalidateContentViewsName() { 620 clearSearch(); 621 contentViewHeaders = null; 622 currentContentViewName = null; 623 } 624 625 @Observer(value = USER_ALL_DOCUMENT_TYPES_SELECTION_CHANGED) 626 public void invalidateContentViewsNameIfChanged() { 627 List<ContentViewHeader> temp = new ArrayList<>( 628 Framework.getLocalService(SearchUIService.class).getContentViewHeaders( 629 actionContextProvider.createActionContext(), navigationContext.getCurrentDocument())); 630 if (temp != null) { 631 if (!temp.equals(contentViewHeaders)) { 632 invalidateContentViewsName(); 633 } 634 if (!temp.isEmpty()) { 635 String s = temp.get(0).getName(); 636 if (s != null && !s.equals(currentContentViewName)) { 637 invalidateContentViewsName(); 638 } 639 } 640 } 641 } 642 643 /** 644 * Reset attributes. 645 */ 646 @Observer(value = { EventNames.FLUSH_EVENT }, create = false) 647 @BypassInterceptors 648 public void resetOnFlush() { 649 contentViewHeaders = null; 650 currentSelectedSavedSearchId = null; 651 currentContentViewName = null; 652 nxqlQuery = DEFAULT_NXQL_QUERY; 653 simpleSearchKeywords = ""; 654 } 655 656 public String getSearchTermParameter() { 657 return SEARCH_TERM_PARAMETER; 658 } 659 660 /** 661 * Triggers content view refresh/reset on saved search. 662 * 663 * @since 8.1 664 */ 665 @Observer(value = { SEARCH_SAVED_EVENT }) 666 public void onSearchSaved() { 667 contentViewActions.refreshOnSeamEvent(SEARCH_SAVED_EVENT); 668 contentViewActions.resetPageProviderOnSeamEvent(SEARCH_SAVED_EVENT); 669 } 670 671}