insanehong 2014-07-16
Search: front side
@5b2dbcabf13877d22c156102d6b001c87e87e670
app/assets/stylesheets/less/_page.less
--- app/assets/stylesheets/less/_page.less
+++ app/assets/stylesheets/less/_page.less
@@ -92,14 +92,16 @@
         list-style: none;
         font-size: 14px;
         color:#788ba7;
-        margin-top:5px;
+        display:block;
 
         li {
-            display: inline-block;
+            float:left;
             position: relative;
+
             a {
-                line-height: 30px;
-                padding:5px 10px;
+                padding:10px;
+                float: none;
+                line-height: 40px;
                 color:#788ba7;
                 text-decoration: none;
                 .transition(color 0.15s);
@@ -221,17 +223,56 @@
     }
 }
 
+.search-box-wrap {
+    border-bottom:1px solid #ddd;
+    padding-bottom:20px;
+
+    input[type="text"] {
+        margin-bottom: 0;
+    }
+}
+
+.gnb-search-form {
+    margin:0;
+    padding:0 10px;
+    font-size: 0;
+    line-height: 30px;
+    margin-top: 5px;
+
+    .dropdown-toggle {
+        .border-radius(3px 0 0 3px);
+        background-color: #F7F7F7;
+    }
+
+    .dropdown-menu > li {
+        clear:both;
+        display:block;
+        float: none;
+
+        a {
+            padding:5px 10px;
+            line-height: 30px;
+        }
+    }
+}
+
 .search-box {
     .border-radius(3px);
     background-color:#FFF;
     height:30px;
+    display: inline-block;
+    vertical-align: middle;
+
+    &.select {
+        .border-radius(0 3px 3px 0);
+    }
 
     input {
         outline:0 none;
         border:0;
-        line-height: 20px;
+        line-height: 30px;
         padding:5px 10px;
-        margin:0;
+        margin-bottom:3px;
         width: 50px;
         .transition(width .3s ease);
 
@@ -244,7 +285,7 @@
         background:transparent;
         border:0;
         outline:0 none;
-        margin: 3px 5px 0 0;
+        margin: 5px;
     }
 
 }
@@ -2632,6 +2673,18 @@
        }
     }
 }
+
+.empty-result {
+    padding:0 20px;
+    margin: 20px 0;
+    text-align: center;
+    min-height: 250px;
+    background-image:url("@{base-image-path}/no_contents.jpg");
+    background-repeat: no-repeat;
+    background-position: center 50%;
+
+}
+
 .attachments {
     ul { list-style-type:none; margin:0; margin-left:18px; }
 
@@ -3338,6 +3391,7 @@
         text-overflow: ellipsis;
         white-space: nowrap;
         overflow: hidden;
+        position: relative;
 
         .post-id {
             color:#999;
@@ -3361,6 +3415,14 @@
                 text-decoration: none;
             }
 
+            &.name { 
+                color : #333;
+                
+                &:hover {
+                    color:#333;
+                }
+            }
+
             &.conflict {
                 color: #b94a48;
 
@@ -3368,6 +3430,7 @@
                     color: #b94a48;
                 }
             }
+
         }
     }
 
@@ -5664,6 +5727,121 @@
   }
 }
 
+.search-list-wrap {
+    list-style: none;
+    display: block;
+
+    li.search-list-item {
+        position: relative;
+        display: block;
+        float: none;
+        margin:0;
+        padding:10px 15px 10px 60px;
+        border-bottom: 1px solid #ddd;
+
+        &.project {
+            padding:10px 15px;
+        }
+    }
+
+    .avatar-wrap {
+        border:1px solid #ececec;
+        width:40px;
+        height:40px;
+        float:left;
+        margin-left:-55px;
+
+        img {
+            width: 100%;
+            height: 100%;
+            vertical-align: top;
+            border: 0 none;
+        }
+
+        &.meta {
+            width:20px;
+            height:20px;
+            float:none;
+            margin-left: 0;
+        }
+
+        &.comment-author {
+            width:20px;
+            height:20px;
+            margin-left: 0;
+        }
+    }
+
+    .title-wrap {
+        line-height: 40px;
+        font-size: 18px;
+        font-weight: bold;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+        overflow: hidden;
+
+        .post-id {
+            color:#999;
+            font-weight: normal;
+
+            
+        }
+
+        .title {
+            color:#333;
+        }
+    }
+
+    .state {
+        margin:0;
+        margin-right: 5px;
+        font-weight: bold;
+        color: #FFF;
+        font-size: 14px;
+        line-height: 20px;
+        padding: 5px 10px;
+        .border-radius(6px);
+    }
+
+    .search-content {
+        display: block;
+        font-size: 14px;
+        margin-top: 15px;
+        border-left: 3px solid #DDD;
+        padding-left:13px;
+    }
+
+    .search-content-body {
+        display: block;
+        margin-top:15px;
+    }
+
+    .search-meta-info {
+        margin-top:15px;
+        font-size: 13px;
+
+        .meta-item {
+            line-height: 20px;
+            margin-right:10px;
+        }
+    }
+
+    .project-link, .user-link {
+        color: #3592b5 !important;
+        font-weight: bold;
+    }
+
+    strong.keyword {
+        background-color: #fffd38;
+        padding:2px;
+    }
+
+    .search-comment-wrap {
+        display: block;
+        position: relative;
+    }
+}
+
 .dropdown-menu>li {
   .my-list-item;
 }
app/controllers/SearchApp.java
--- app/controllers/SearchApp.java
+++ app/controllers/SearchApp.java
@@ -9,7 +9,8 @@
 import org.apache.commons.lang3.StringUtils;
 import play.mvc.Controller;
 import play.mvc.Result;
-import views.html.search.result;
+import views.html.search.*;
+import utils.HttpUtil;
 
 import java.util.List;
 
@@ -26,6 +27,7 @@
      * @return
      */
     public static Result searchAllRepos() {
+        // SearchCondition from param
         String searchTypeValue = request().getQueryString("searchType");
         String keyword = request().getQueryString("keyword");
         setPage();
@@ -143,7 +145,7 @@
                 break;
             case REVIEW:
                 searchResult.setReviews(Search.findReviews(keyword, user, organization, DEFAULT_PAGE));
-                break;
+                break;            
         }
 
         return ok(result.render("title.search", organization, null, searchResult));
app/models/enumeration/SearchType.java
--- app/models/enumeration/SearchType.java
+++ app/models/enumeration/SearchType.java
@@ -14,6 +14,10 @@
         this.searchType = value;
     }
 
+    public String getType() {
+        return this.searchType;
+    }
+
     public static SearchType getValue(String value) {
         for (SearchType searchType : SearchType.values()) {
             if (searchType.searchType.equals(value)) {
app/views/common/navbar.scala.html
--- app/views/common/navbar.scala.html
+++ app/views/common/navbar.scala.html
@@ -18,7 +18,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  **@
-@(menuType:utils.MenuType, isProject:Boolean)
+@(menuType:utils.MenuType, project:Project, org:Organization)
 
 @import utils._
 
@@ -30,6 +30,16 @@
     play.Configuration.root().getString("application.feedback.url")
 }
 
+@makeSearchLink() = @{
+    if(project != null) {
+        routes.SearchApp.searchProject(project.owner, project.name)
+    } else if (org !=null) {
+        routes.SearchApp.searchGroupRepos(org.name)
+    } else {
+        routes.SearchApp.searchAllRepos()
+    }
+}
+
 <div class="unsupported">
     <div class="unsupported-inner">
         <p id="unsupported-content">
@@ -38,7 +48,7 @@
         </p>
     </div>
 </div>
-<header class="gnb-outer @if(isProject) {project-header}">
+<header class="gnb-outer @if(project !=null) {project-header}">
     <div class="gnb-inner">
         <a href="@routes.Application.index()" class="logo"><h1 class="blind">@utils.Config.getSiteName</h1></a>
         <ul class="gnb-nav">
@@ -53,6 +63,55 @@
                 <a href="@appFeedbackUrl" target="_blank">@Messages("title.yobi.feedback")</a>
             </li>
             }
+            <li>
+                <form action="@makeSearchLink()" class="input-prepend gnb-search-form" name="gnb-search-form">
+                <input type="hidden" name="searchType" value="issue">
+                    @if(project != null || org !=null) {
+                    
+                    <div class="btn-group">
+                        <button class="ybtn dropdown-toggle" data-toggle="dropdown" type="button" id="gnb-search-scope-title">
+                            @if(project != null) {
+                                @Messages("search.scope.porject")
+                            } else {
+                                @Messages("search.scope.group")
+                            }
+                        </button>
+                        <ul class="dropdown-menu flat right">
+                            @if(project != null) {
+                            <li>
+                                <a href="#" data-toggle="search-scope" data-action="@routes.SearchApp.searchProject(project.owner, project.name)">
+                                    @Messages("search.scope.porject")
+                                </a>
+                            </li>
+                            @if(project.hasGroup) {
+                            <li>
+                                <a href="#" data-toggle="search-scope" data-action="@routes.SearchApp.searchGroupRepos(project.owner)">
+                                    @Messages("search.scope.group")
+                                </a>
+                            </li>
+                            }
+                            } 
+                            @if(org != null) {
+                            <li>
+                                <a href="#" data-toggle="search-scope" data-action="@routes.SearchApp.searchGroupRepos(org.name)">
+                                    @Messages("search.scope.group")
+                                </a>
+                            </li>
+                            }
+                            <li>
+                                <a href="#" data-toggle="search-scope" data-action="@routes.SearchApp.searchAllRepos()">
+                                    @Messages("search.scope.all")
+                                </a>
+                            </li>
+                        </ul>
+                    </div>
+                    }
+                    <div class="search-box @if(project != null || org !=null) {select}">
+                        <input type="text" name="keyword" autocomplete="off" accesskey="S">
+                        <button type="submit"><i class="yobicon-search"></i></button>
+                    </div>
+                </form>
+            </li>
         </ul>
         @common.usermenu(null)
     </div>
app/views/common/scripts.scala.html
--- app/views/common/scripts.scala.html
+++ app/views/common/scripts.scala.html
@@ -179,5 +179,10 @@
             }
         }
 
+        $('[data-toggle="search-scope"]').on('click', function() {
+            $('form[name="gnb-search-form"]').attr('action', $(this).data('action'));
+            $('#gnb-search-scope-title').text($(this).text());
+        });
+
     });
 </script>
app/views/common/usermenu.scala.html
--- app/views/common/usermenu.scala.html
+++ app/views/common/usermenu.scala.html
@@ -22,14 +22,6 @@
 @import utils.TemplateHelper._
 @orderString = @{"createdDate DESC"}
 <ul class="gnb-usermenu">
-    <li>
-        <form action="@routes.ProjectApp.projects()">
-            <div class="search-box">
-                <input type="text" name="filter" autocomplete="off" accesskey="S">
-                <button type="submit"><i class="yobicon-search"></i></button>
-            </div>
-        </form>
-    </li>
     @if(session.contains("loginId")){
     <li class="gnb-usermenu-dropdown">
         <a href="javascript:void(0);" class="gnb-dropdown-toggle dropdwon-box-btn" data-toggle="dropdown">
app/views/organization/view.scala.html
--- app/views/organization/view.scala.html
+++ app/views/organization/view.scala.html
@@ -44,7 +44,7 @@
 }
 }
 
-@siteLayout(org.name, utils.MenuType.NONE) {
+@organizationLayout(org.name, utils.MenuType.NONE, org) {
 @header(org)
 @menu(org)
 
 
app/views/organizationLayout.scala.html (added)
+++ app/views/organizationLayout.scala.html
@@ -0,0 +1,31 @@
+@**
+* Yobi, Project Hosting SW
+*
+* Copyright 2013 NAVER Corp.
+* http://yobi.io
+*
+* @Author Insanehong
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*   http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+**@
+@(title: String, menuType:utils.MenuType, group: Organization)(content: Html)
+
+@import utils._
+
+@layout(Messages(title))(""){
+    @common.navbar(menuType, null, group)
+    
+    @content
+    
+    @common.footer()
+}
app/views/projectLayout.scala.html
--- app/views/projectLayout.scala.html
+++ app/views/projectLayout.scala.html
@@ -23,7 +23,7 @@
 @import utils._
 
 @layout(Messages(title) + " (" + project.name + ")")("prj") {
-    @common.navbar(menuType, true)
+    @common.navbar(menuType, project, null)
     
     @views.html.project.header(project)
 
 
app/views/search/partial_issue_comments.scala.html (added)
+++ app/views/search/partial_issue_comments.scala.html
@@ -0,0 +1,96 @@
+@**
+* Yobi, Project Hosting SW
+*
+* Copyright 2014 NAVER Corp.
+* http://yobi.io
+*
+* @Author Insanehong 
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*   http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+**@
+
+@(group: Organization, project: Project, searchResult: SearchResult)
+
+@import utils.TemplateHelper._
+@import utils.JodaDateUtil
+
+@defining(searchResult.getIssueComments) { page =>
+    @if(page.getList.length > 0) {
+    <ul class="search-list-wrap">
+        @for(comment <- page.getList) {
+            @defining(User.findByLoginId(comment.authorLoginId)){ user =>
+            <li class="search-list-item @if(project != null) {project}">
+                @if(project == null) {
+                <a href="@routes.ProjectApp.project(comment.issue.project.owner, comment.issue.project.name)" class="avatar-wrap">
+                    <img src="@urlToProjectLogo(comment.issue.project)">
+                </a>
+                }
+                <div class="title-wrap">
+                    <span class="state @comment.issue.state.state.toLowerCase">@Messages("issue.state." + comment.issue.state.state.toLowerCase)</span>
+                    <span class="post-id">#@comment.issue.getNumber</span>
+                    <a href="@routes.IssueApp.issue(comment.issue.project.owner, comment.issue.project.name, comment.issue.getNumber)#comment-@comment.id">
+                        Re) @comment.issue.title
+                    </a>
+                </div>
+                <div class="search-content">
+                   @defining(searchResult.makeSnipets(comment.contents, 40)) { snipets =>
+                        @if(snipets != null && snipets.size > 0) {
+                            @for(snipet <- snipets) {
+                            <p class="search-content-body">
+                                @snipet @if(snipet.size < comment.contents.size) { ..... }
+                            </p>
+                            }
+                        }
+                    }                        
+                </div>
+                <div class="search-meta-info">
+                    @if(project == null) {
+                    <a href="@routes.ProjectApp.project(comment.issue.project.owner, comment.issue.project.name)" class="project-link meta-item">
+                        @comment.issue.project.owner/@comment.issue.project.name
+                    </a>
+                    }
+                    <a href="@routes.UserApp.userInfo(user.loginId)" class="avatar-wrap meta" data-toggle="tooltip" data-placement="top" title="@user.loginId">
+                        @if(user.avatarUrl == UserApp.DEFAULT_AVATAR_URL){
+                            <img src="@urlToPicture(user.email, 16)">
+                        } else {
+                            <img src="@user.avatarUrl" alt="@user.name" width="16" height="16"/>
+                        }
+                    </a>
+                    @if(user.name){
+                        <a href="@routes.UserApp.userInfo(user.loginId)" class="meta-item" data-toggle="tooltip" data-placement="top" title="@user.loginId">
+                            @user.name
+                        </a>
+                    } else {
+                        <span class="meta-item">@Messages("issue.noAuthor")</span>
+                    }
+
+                    <span class="meta-item" title="@JodaDateUtil.getDateString(comment.createdDate)">
+                        @agoOrDateString(comment.createdDate)
+                    </span>               
+                </div>                
+            </li>
+            }
+        }
+    </ul>
+    <!-- pagination.js will fill here. -->
+    <div id="pagination"></div>
+
+    <script type="text/javascript">
+        $(document).ready(function(){
+            yobi.Pagination.update($("#pagination"), @page.getTotalPageCount);
+        });
+    </script>
+    } else {
+        <div class="empty-result"></div>
+    }
+}
 
app/views/search/partial_issues.scala.html (added)
+++ app/views/search/partial_issues.scala.html
@@ -0,0 +1,99 @@
+@**
+* Yobi, Project Hosting SW
+*
+* Copyright 2014 NAVER Corp.
+* http://yobi.io
+*
+* @Author Insanehong 
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*   http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+**@
+
+@(group: Organization, project: Project, searchResult: SearchResult)
+
+@import utils.TemplateHelper._
+@import utils.JodaDateUtil
+
+@urlToList(project:Project, state:String) = {@routes.IssueApp.issues(project.owner, project.name, "open", "html", 1)}
+
+@defining(searchResult.getIssues) { page =>
+    @if(page.getList.length > 0) {
+    <ul class="search-list-wrap">
+        @for(issue <- page.getList) {
+            @defining(User.findByLoginId(issue.authorLoginId)){ user =>
+            <li class="search-list-item @if(project != null) {project}">
+                @if(project == null) {
+                <a href="@routes.ProjectApp.project(issue.project.owner, issue.project.name)" class="avatar-wrap">
+                    <img src="@urlToProjectLogo(issue.project)">
+                </a>
+                }
+                <div class="title-wrap">
+                     <span class="state @issue.state.state.toLowerCase">@Messages("issue.state." + issue.state.state.toLowerCase)</span>
+                    <span class="post-id">#@issue.getNumber</span>
+                    <a href="@routes.IssueApp.issue(issue.project.owner, issue.project.name, issue.getNumber)" class="title">
+                        @issue.title
+                    </a>
+                </div>
+                <div class="search-content">
+                    @defining(searchResult.makeSnipets(issue.body, 40)) { snipets =>
+                        @if(snipets != null && snipets.size > 0) {
+                            @for(snipet <- snipets) {
+                            <p class="search-content-body">
+                                @snipet @if(snipet.size < issue.body.size) { ..... }
+                            </p>
+                            }
+                        }
+                    }
+                </div>
+                <div class="search-meta-info">
+                    @if(project == null) {
+                    <a href="@routes.ProjectApp.project(issue.project.owner,issue.project.name)" class="project-link meta-item">
+                        @issue.project.owner/@issue.project.name
+                    </a>
+                    }
+                    <a href="@routes.UserApp.userInfo(user.loginId)" class="avatar-wrap meta" data-toggle="tooltip" data-placement="top" title="@user.loginId">
+                        @if(user.avatarUrl == UserApp.DEFAULT_AVATAR_URL){
+                            <img src="@urlToPicture(user.email, 16)">
+                        } else {
+                            <img src="@user.avatarUrl" alt="@user.name" width="16" height="16"/>
+                        }
+                    </a>
+                    @if(user.name){
+                        <a href="@routes.UserApp.userInfo(user.loginId)" class="meta-item" data-toggle="tooltip" data-placement="top" title="@user.loginId">
+                            @user.name
+                        </a>
+                    } else {
+                        <span class="meta-item">@Messages("issue.noAuthor")</span>
+                    }
+
+                    <span class="meta-item" title="@JodaDateUtil.getDateString(issue.createdDate)">
+                        @agoOrDateString(issue.createdDate)
+                    </span>               
+                </div>
+            </li>
+            }
+        }
+    </ul>    
+    <!-- pagination.js will fill here. -->
+    <div id="pagination"></div>
+
+    <script type="text/javascript">
+        $(document).ready(function(){
+            yobi.Pagination.update($("#pagination"), @page.getTotalPageCount);
+        });
+    </script>
+    } else {
+        <div class="empty-result"></div>
+    }
+
+}
 
app/views/search/partial_milestones.scala.html (added)
+++ app/views/search/partial_milestones.scala.html
@@ -0,0 +1,87 @@
+@**
+* Yobi, Project Hosting SW
+*
+* Copyright 2014 NAVER Corp.
+* http://yobi.io
+*
+* @Author Insanehong 
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*   http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+**@
+
+@(group: Organization, project: Project, searchResult: SearchResult)
+
+@import utils.JodaDateUtil
+@import utils.TemplateHelper._
+@import utils.AccessControl._
+@import scala.collection.immutable._
+@import models.enumeration.ResourceType
+@import models.enumeration.Operation
+
+
+@makeIssuesLink(mId: Long, _state: String, project: Project) = @{
+    buildQueryString(routes.IssueApp.issues(project.owner, project.name, _state),Map("milestoneId"->mId.toString))
+}
+
+@defining(searchResult.getMilestones) { page =>
+    @if(page.getList.length > 0) {
+    <ul class="search-list-wrap">
+        @for(milestone <- page.getList) {
+        <li class="search-list-item @if(project != null) {project}">
+            @if(project == null) {
+            <a href="@routes.ProjectApp.project(milestone.project.owner, milestone.project.name)" class="avatar-wrap">
+                <img src="@urlToProjectLogo(milestone.project)">
+            </a>
+            }
+            <div class="title-wrap">
+                 <span class="state @milestone.state.state.toLowerCase">@Messages("milestone.state." + milestone.state.state.toLowerCase)</span>
+                <a href="@routes.MilestoneApp.milestone(milestone.project.owner, milestone.project.name, milestone.id)" class="title">
+                    @milestone.title
+                </a>
+            </div>
+            <div class="search-content">
+                @defining(searchResult.makeSnipets(milestone.contents, 40)) { snipets =>
+                    @if(snipets != null && snipets.size > 0) {
+                        @for(snipet <- snipets) {
+                        <p class="search-content-body">
+                            @snipet @if(snipet.size < milestone.contents.size) { ..... }
+                        </p>
+                        }
+                    }
+                }
+            </div>
+            <div class="search-meta-info">
+                @if(project == null) {
+                <a href="@routes.ProjectApp.project(milestone.project.owner,milestone.project.name)" class="project-link meta-item">
+                    @milestone.project.owner/@milestone.project.name
+                </a>
+                }
+                @if(milestone.dueDate != null) {
+                <span class="due-date meta-item">@Messages("label.dueDate") <strong>@milestone.getDueDateString</strong> (@milestone.until)</span>
+                }
+            </div>
+        </li>
+        }
+    </ul>
+    <!-- pagination.js will fill here. -->
+    <div id="pagination"></div>
+
+    <script type="text/javascript">
+        $(document).ready(function(){
+            yobi.Pagination.update($("#pagination"), @page.getTotalPageCount);
+        });
+    </script>
+    } else {
+        <div class="empty-result"></div>
+    }
+}
 
app/views/search/partial_post_comments.scala.html (added)
+++ app/views/search/partial_post_comments.scala.html
@@ -0,0 +1,95 @@
+@**
+* Yobi, Project Hosting SW
+*
+* Copyright 2014 NAVER Corp.
+* http://yobi.io
+*
+* @Author Insanehong 
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*   http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+**@
+
+@(group: Organization, project: Project, searchResult: SearchResult)
+
+@import utils.TemplateHelper._
+@import utils.JodaDateUtil
+
+@defining(searchResult.getPostComments) { page =>
+    @if(page.getList.length > 0) {
+    <ul class="search-list-wrap">
+        @for(comment <- page.getList) {
+            @defining(User.findByLoginId(comment.authorLoginId)){ user =>
+            <li class="search-list-item @if(project != null) {project}">
+                @if(project == null) {
+                <a href="@routes.ProjectApp.project(comment.posting.project.owner, comment.posting.project.name)" class="avatar-wrap">
+                    <img src="@urlToProjectLogo(comment.posting.project)">
+                </a>
+                }
+                <div class="title-wrap">
+                    <span class="post-id">#@comment.posting.getNumber</span>
+                    <a href="@routes.BoardApp.post(comment.posting.project.owner, comment.posting.project.name, comment.posting.getNumber)#comment-@comment.id">
+                        Re) @comment.posting.title
+                    </a>
+                </div>
+                <div class="search-content">
+                   @defining(searchResult.makeSnipets(comment.contents, 40)) { snipets =>
+                        @if(snipets != null && snipets.size > 0) {
+                            @for(snipet <- snipets) {
+                            <p class="search-content-body">
+                                @snipet @if(snipet.size < comment.contents.size) { ..... }
+                            </p>
+                            }
+                        }
+                    }                        
+                </div>
+                <div class="search-meta-info">
+                    @if(project == null) {
+                    <a href="@routes.ProjectApp.project(comment.posting.project.owner, comment.posting.project.name)" class="project-link meta-item">
+                        @comment.posting.project.owner/@comment.posting.project.name
+                    </a>
+                    }
+                    <a href="@routes.UserApp.userInfo(user.loginId)" class="avatar-wrap meta" data-toggle="tooltip" data-placement="top" title="@user.loginId">
+                        @if(user.avatarUrl == UserApp.DEFAULT_AVATAR_URL){
+                            <img src="@urlToPicture(user.email, 16)">
+                        } else {
+                            <img src="@user.avatarUrl" alt="@user.name" width="16" height="16"/>
+                        }
+                    </a>
+                    @if(user.name){
+                        <a href="@routes.UserApp.userInfo(user.loginId)" class="meta-item" data-toggle="tooltip" data-placement="top" title="@user.loginId">
+                            @user.name
+                        </a>
+                    } else {
+                        <span class="meta-item">@Messages("posting.noAuthor")</span>
+                    }
+
+                    <span class="meta-item" title="@JodaDateUtil.getDateString(comment.createdDate)">
+                        @agoOrDateString(comment.createdDate)
+                    </span>               
+                </div>                
+            </li>
+            }
+        }
+    </ul>
+    <!-- pagination.js will fill here. -->
+    <div id="pagination"></div>
+
+    <script type="text/javascript">
+        $(document).ready(function(){
+            yobi.Pagination.update($("#pagination"), @page.getTotalPageCount);
+        });
+    </script>
+    } else {
+        <div class="empty-result"></div>
+    }
+}
 
app/views/search/partial_posts.scala.html (added)
+++ app/views/search/partial_posts.scala.html
@@ -0,0 +1,95 @@
+@**
+* Yobi, Project Hosting SW
+*
+* Copyright 2014 NAVER Corp.
+* http://yobi.io
+*
+* @Author Insanehong 
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*   http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+**@
+
+@(group: Organization, project: Project, searchResult: SearchResult)
+
+@import utils.TemplateHelper._
+@import utils.JodaDateUtil
+
+@defining(searchResult.getPosts) { page =>
+    @if(page.getList.length > 0) {
+    <ul class="search-list-wrap">
+        @for(post <- page.getList) {
+            @defining(User.findByLoginId(post.authorLoginId)){ user =>
+            <li class="search-list-item @if(project != null) {project}">
+                @if(project == null) {
+                <a href="@routes.ProjectApp.project(post.project.owner, post.project.name)" class="avatar-wrap">
+                    <img src="@urlToProjectLogo(post.project)">
+                </a>
+                }
+                <div class="title-wrap">
+                    <span class="post-id">#@post.getNumber</span>
+                    <a href="@routes.BoardApp.post(post.project.owner, post.project.name, post.getNumber)" class="title">
+                        @post.title
+                    </a>
+                </div>
+                <div class="search-content">
+                    @defining(searchResult.makeSnipets(post.body, 40)) { snipets =>
+                        @if(snipets != null && snipets.size > 0) {
+                            @for(snipet <- snipets) {
+                            <p class="search-content-body">
+                                @snipet @if(snipet.size < post.body.size) { ..... }
+                            </p>
+                            }
+                        }
+                    }
+                </div>
+                <div class="search-meta-info">
+                    @if(project == null) {
+                    <a href="@routes.ProjectApp.project(post.project.owner,post.project.name)" class="project-link meta-item">
+                        @post.project.owner/@post.project.name
+                    </a>
+                    }
+                    <a href="@routes.UserApp.userInfo(user.loginId)" class="avatar-wrap meta" data-toggle="tooltip" data-placement="top" title="@user.loginId">
+                        @if(user.avatarUrl == UserApp.DEFAULT_AVATAR_URL){
+                            <img src="@urlToPicture(user.email, 32)">
+                        } else {
+                            <img src="@user.avatarUrl" alt="@user.name" width="32" height="32"/>
+                        }
+                    </a>
+                    @if(user.name){
+                        <a href="@routes.UserApp.userInfo(user.loginId)" class="meta-item" data-toggle="tooltip" data-placement="top" title="@user.loginId">
+                            @user.name
+                        </a>
+                    } else {
+                        <span class="meta-item">@Messages("issue.noAuthor")</span>
+                    }
+
+                    <span class="meta-item" title="@JodaDateUtil.getDateString(post.createdDate)">
+                        @agoOrDateString(post.createdDate)
+                    </span>
+                </div>
+            </li>
+            }
+        }
+    </ul>    
+    <!-- pagination.js will fill here. -->
+    <div id="pagination"></div>
+
+    <script type="text/javascript">
+        $(document).ready(function(){
+            yobi.Pagination.update($("#pagination"), @page.getTotalPageCount);
+        });
+    </script>
+    } else {
+        <div class="empty-result"></div>
+    }
+}
 
app/views/search/partial_projects.scala.html (added)
+++ app/views/search/partial_projects.scala.html
@@ -0,0 +1,78 @@
+@**
+* Yobi, Project Hosting SW
+*
+* Copyright 2014 NAVER Corp.
+* http://yobi.io
+*
+* @Author Insanehong 
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*   http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+**@
+
+@(group: Organization, project: Project, searchResult: SearchResult)
+
+@import utils.TemplateHelper._
+@import utils.JodaDateUtil._
+
+@defining(searchResult.getProjects) { page =>
+    @if(page.getList.length > 0) {
+    <ul class="search-list-wrap">
+        @for(project <- page.getList) {
+            @defining(User.findByLoginId(project.owner)){ user =>
+            <li class="search-list-item">
+                <a href="@routes.ProjectApp.project(project.owner, project.name)" class="avatar-wrap">
+                    <img src="@urlToProjectLogo(project)">
+                </a>
+                <div class="title-wrap">
+                    <a href="@routes.ProjectApp.project(project.owner, project.name)" class="title project-link">
+                    @project.owner/@project.name
+                    </a>
+                </div>
+                @if(project.isForkedFromOrigin){
+                <div class="search-meta-info nm">
+                    <span>
+                       <i class="yobicon-split yobicon-white vmiddle"></i>
+                        @Messages("fork.original")
+                    </span>
+                    <span>
+                        <a href="@routes.ProjectApp.project(project.originalProject.owner, project.originalProject.name)" class="project-link">
+                            @project.originalProject.owner/@project.originalProject.name
+                        </a>
+                    </span>
+                </div>
+                }
+                <div class="search-content">
+                    <p class="search-content-body">
+                        @project.overview
+                    </p>
+                 </div>
+                 <div class="search-meta-info">
+                    <span class="meta-info">
+                        @Messages("project.create")
+                        <strong title="@getDateString(project.createdDate)">@agoOrDateString(project.createdDate)</strong>
+                    </span>
+                    @if(project.lastPushedDateAgo() != null) {
+                    <span class="meta-info">
+                        @Messages("project.codeUpdate")
+                        <strong title="@getDateString(project.lastPushedDate)">@agoOrDateString(project.lastPushedDate)</strong>
+                    </span>
+                    }
+                 </div>
+            </li>
+            }
+        }
+    </ul>
+    } else {
+        <div class="empty-result"></div>
+    }
+}
 
app/views/search/partial_reviews.scala.html (added)
+++ app/views/search/partial_reviews.scala.html
@@ -0,0 +1,98 @@
+@**
+* Yobi, Project Hosting SW
+*
+* Copyright 2014 NAVER Corp.
+* http://yobi.io
+*
+* @Author Insanehong 
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*   http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+**@
+
+@(group: Organization, project: Project, searchResult: SearchResult)
+
+@import utils.TemplateHelper._
+@import utils.JodaDateUtil
+@import utils.TemplateHelper.DiffRenderer._
+
+@defining(searchResult.getReviews) { page =>
+    @if(page.getList.length > 0) {
+    <ul class="search-list-wrap">
+        @for(review <- page.getList) {
+            <li class="search-list-item @if(project != null) {project}">
+            @defining(User.findByLoginId(review.author.loginId)){ user =>
+                @if(review.thread.pullRequest != null) {
+                @if(project == null) {
+                <a href="@routes.ProjectApp.project(review.thread.project.owner, review.thread.project.name)" class="avatar-wrap">
+                    <img src="@urlToProjectLogo(review.thread.project)">
+                </a>
+                }
+                <div class="title-wrap">
+                    <span class="post-id">#@review.thread.pullRequest.number</span>
+                    <a href="@DiffRenderer.urlToCommentThread(review.thread)">
+                        Re) @review.thread.pullRequest.title
+                    </a>
+                </div>
+                }
+                <div class="search-content">
+                   @defining(searchResult.makeSnipets(review.getContents, 40)) { snipets =>
+                        @if(snipets != null && snipets.size > 0) {
+                            @for(snipet <- snipets) {
+                            <p class="search-content-body">
+                                @snipet @if(snipet.size < review.getContents.size) { ..... }
+                            </p>
+                            }
+                        }
+                    }                        
+                </div>
+                <div class="search-meta-info">
+                    @if(project == null) {
+                    <a href="@routes.ProjectApp.project(review.thread.project.owner, review.thread.project.name)" class="project-link meta-item">
+                        @review.thread.project.owner/@review.thread.project.name
+                    </a>
+                    }
+                    <a href="@routes.UserApp.userInfo(user.loginId)" class="avatar-wrap meta" data-toggle="tooltip" data-placement="top" title="@user.loginId">
+                        @if(user.avatarUrl == UserApp.DEFAULT_AVATAR_URL){
+                            <img src="@urlToPicture(user.email, 16)">
+                        } else {
+                            <img src="@user.avatarUrl" alt="@user.name" width="16" height="16"/>
+                        }
+                    </a>
+                    @if(user.name){
+                        <a href="@routes.UserApp.userInfo(user.loginId)" class="meta-item" data-toggle="tooltip" data-placement="top" title="@user.loginId">
+                            @user.name
+                        </a>
+                    } else {
+                        <span class="meta-item">@Messages("issue.noAuthor")</span>
+                    }
+                    <span class="meta-item" title="@JodaDateUtil.getDateString(review.createdDate)">
+                        @agoOrDateString(review.createdDate)
+                    </span>               
+       
+                </div>             
+            </li>
+            }
+        }
+    </ul>
+    <!-- pagination.js will fill here. -->
+    <div id="pagination"></div>
+
+    <script type="text/javascript">
+        $(document).ready(function(){
+            yobi.Pagination.update($("#pagination"), @page.getTotalPageCount);
+        });
+    </script>
+    } else {
+        <div class="empty-result"></div>
+    }
+}(No newline at end of file)
 
app/views/search/partial_search.scala.html (added)
+++ app/views/search/partial_search.scala.html
@@ -0,0 +1,167 @@
+@**
+* Yobi, Project Hosting SW
+*
+* Copyright 2014 NAVER Corp.
+* http://yobi.io
+*
+* @Author Insanehong 
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*   http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+**@
+
+@(group: Organization, project: Project, searchResult: SearchResult)
+
+@isActiveMenu(search_type:SearchType) = @{
+    if(search_type == searchResult.getSearchType()){ "class=active" }
+}
+
+@makeSearchLink() = @{
+    if(project != null) {
+        routes.SearchApp.searchProject(project.owner, project.name)
+    } else if (group !=null) {
+        routes.SearchApp.searchGroupRepos(group.name)
+    } else {
+        routes.SearchApp.searchAllRepos()
+    }
+}
+
+<div class="site-breadcrumb-outer">
+    <div class="site-breadcrumb-inner">
+        <h3>
+            @Messages("title.search")
+        </h3>
+    </div>
+</div>
+<div class="page-wrap-outer">
+    <div class="project-page-wrap">
+        <div class="project-page-wrap">
+            <div class="row-fluid">
+                <div class="span2">
+                    <ul class="lst-stacked unstyled search-category-wrap">
+                        <li @isActiveMenu(SearchType.ISSUE)>
+                            <a href="#" data-toggle="search-category" data-type="@SearchType.ISSUE.getType()">
+                                @Messages("search.menu.issues")
+                                <span class="num-badge pull-right">@searchResult.getIssuesCount</span>
+                            </a>
+                        </li>
+                        <li @isActiveMenu(SearchType.USER)>
+                            <a href="#" data-toggle="search-category" data-type="@SearchType.USER.getType()">
+                                @Messages("search.menu.users")
+                                <span class="num-badge pull-right">@searchResult.getUsersCount</span>
+                            </a>
+                        </li>
+                        @if(project == null) {
+                        <li @isActiveMenu(SearchType.PROJECT)>
+                            <a href="#" data-toggle="search-category" data-type="@SearchType.PROJECT.getType()">
+                                @Messages("search.menu.projects")
+                                <span class="num-badge pull-right">@searchResult.getProjectsCount</span>
+                            </a>    
+                        </li>
+                        }
+                        <li @isActiveMenu(SearchType.POST)>
+                            <a href="#" data-toggle="search-category" data-type="@SearchType.POST.getType()">
+                                @Messages("search.menu.boards")
+                                <span class="num-badge pull-right">@searchResult.getPostsCount</span>
+                            </a>
+                        </li>
+                        <li @isActiveMenu(SearchType.MILESTONE)>
+                            <a href="#" data-toggle="search-category" data-type="@SearchType.MILESTONE.getType()">
+                                @Messages("search.menu.milestones")
+                                <span class="num-badge pull-right">@searchResult.getMilestonesCount</span>
+                            </a>
+                        </li>
+                        <li @isActiveMenu(SearchType.ISSUE_COMMENT)>
+                            <a href="#" data-toggle="search-category" data-type="@SearchType.ISSUE_COMMENT.getType()">
+                                @Messages("search.menu.issue.comments")
+                                <span class="num-badge pull-right">@searchResult.getIssueCommentsCount</span>
+                            </a>
+                        </li>
+                        <li @isActiveMenu(SearchType.POST_COMMENT)>
+                            <a href="#" data-toggle="search-category" data-type="@SearchType.POST_COMMENT.getType()">
+                                @Messages("search.menu.board.comments") 
+                                <span class="num-badge pull-right">@searchResult.getPostCommentsCount</span>
+                            </a>
+                        </li>
+                        <li @isActiveMenu(SearchType.REVIEW)>
+                            <a href="#" data-toggle="search-category" data-type="@SearchType.REVIEW.getType()">
+                                @Messages("search.menu.reviews")
+                                <span class="num-badge pull-right">@searchResult.getReviewsCount</span>
+                            </a>
+                        </li>
+                    </ul>
+                </div>
+                <div class="span10">
+                    <div class="search-box-wrap">
+                        <form id="searchInnerForm" method="get" action="@makeSearchLink()" > 
+                        <input type="hidden" name="searchType" value="@searchResult.getSearchType().getType()">    
+                            <input type="text" name="keyword" class="span11" value="@searchResult.getKeyword()">
+                            <button type="submit" class="ybtn">@Messages("title.search")</button>
+                        </form>
+                    </div>
+                    <div class="search-result-wrap">
+                        @if(searchResult.getSearchType() == SearchType.ISSUE) {
+                            @partial_issues(group, project, searchResult)
+                        }
+
+                        @if(searchResult.getSearchType() == SearchType.USER) {
+                            @partial_users(group, project, searchResult)
+                        }
+
+                        @if(searchResult.getSearchType() == SearchType.PROJECT) {
+                            @partial_projects(group, project, searchResult)
+                        }
+
+                        @if(searchResult.getSearchType() == SearchType.POST) {
+                            @partial_posts(group, project, searchResult)
+                        }
+
+                        @if(searchResult.getSearchType() == SearchType.MILESTONE) {
+                            @partial_milestones(group, project, searchResult)
+                        }
+
+                        @if(searchResult.getSearchType() == SearchType.ISSUE_COMMENT) {
+                            @partial_issue_comments(group, project, searchResult)
+                        }
+
+                        @if(searchResult.getSearchType() == SearchType.POST_COMMENT) {
+                            @partial_post_comments(group, project, searchResult)
+                        }
+
+                        @if(searchResult.getSearchType() == SearchType.REVIEW) {
+                            @partial_reviews(group, project, searchResult)
+                        }
+                    </div>
+                </div>
+            </div>
+        </div>        
+    </div>
+</div>
+
+<script>
+$(function(){
+    $('.search-category-wrap').on('click', 'a[data-toggle="search-category"]', function(event) {
+        event.preventDefault();
+        $('#searchInnerForm').find('input[name="searchType"]').val($(this).data('type'));
+        $('#searchInnerForm').submit();
+    });
+
+    $('.search-content-body, .title').each(function() {
+        var content = $(this).html();
+        content = content.replace(/@searchResult.getKeyword()/ig, function(match) {
+            return "<strong class=\"keyword\">"+ match +"</strong>";
+        });
+
+        $(this).html(content);
+    })
+});
+</script>(No newline at end of file)
 
app/views/search/partial_users.scala.html (added)
+++ app/views/search/partial_users.scala.html
@@ -0,0 +1,64 @@
+@**
+* Yobi, Project Hosting SW
+*
+* Copyright 2014 NAVER Corp.
+* http://yobi.io
+*
+* @Author Insanehong 
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*   http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+**@
+
+@(group: Organization, project: Project, searchResult: SearchResult)
+
+@import utils.TemplateHelper._
+@import utils.JodaDateUtil
+
+@defining(searchResult.getUsers) { page =>
+    @if(page.getList.length > 0) {
+    <ul class="search-list-wrap">
+        @for(user <- page.getList) {
+            <li class="search-list-item">
+            <a href="@routes.UserApp.userInfo(user.loginId)" class="avatar-wrap" data-toggle="tooltip" data-placement="top" title="@user.loginId">
+            @if(user.avatarUrl == UserApp.DEFAULT_AVATAR_URL){
+                <img src="@urlToPicture(user.email, 32)">
+            } else {
+                <img src="@user.avatarUrl" alt="@user.name" width="32" height="32"/>
+            }
+            </a>
+
+            <div class="title-wrap">
+                <a href="@routes.UserApp.userInfo(user.loginId)" class="title user-link">
+                    @user.name (@{"@"}@user.loginId)
+                </a>
+            </div>
+            <div class="infos nm">
+                <span class="infos-item">
+                    @Messages("userinfo.since") @user.getDateString
+                </span>
+            </div>
+        </li>
+        }
+    </ul>
+    <!-- pagination.js will fill here. -->
+    <div id="pagination"></div>
+
+    <script type="text/javascript">
+        $(document).ready(function(){
+            yobi.Pagination.update($("#pagination"), @page.getTotalPageCount);
+        });
+    </script>
+    } else {
+        <div class="empty-result"></div>
+    }
+}
app/views/search/result.scala.html
--- app/views/search/result.scala.html
+++ app/views/search/result.scala.html
@@ -23,224 +23,22 @@
 @import utils.TemplateHelper._
 @import utils.JodaDateUtil
 
-@siteLayout(message, utils.MenuType.NONE) {
-<div class="site-breadcrumb-outer">
-    <div class="site-breadcrumb-inner">
-        <h3>
-            @if(group != null) {> @group.name}
-            @if(project != null) {> @project.owner/@project.name}
-            > "@searchResult.getKeyword()"
-        </h3>
-    </div>
-</div>
-<div class="page-wrap-outer">
-    <div class="project-page-wrap">
-        <h4></h4>
-        <ul>
-            <li>Issues Count: @searchResult.getIssuesCount</li>
-            <li>Users Count: @searchResult.getUsersCount</li>
-            @if(project == null) {
-            <li>Projects Count: @searchResult.getProjectsCount</li>
-            }
-            <li>Posts Count: @searchResult.getPostsCount</li>
-            <li>Milestones Count: @searchResult.getMilestonesCount</li>
-            <li>IssueComments Count: @searchResult.getIssueCommentsCount</li>
-            <li>PostComments Count: @searchResult.getPostCommentsCount</li>
-            <li>Reviews Count: @searchResult.getReviewsCount</li>
-        </ul>
 
-        @defining(searchResult.getIssues) { page =>
-            @if(page != null) {
-            <h4>Issues</h4>
-            <ul>
-                @for(issue <- page.getList) {
-                <li>#@issue.getNumber @issue.title
-                    @defining(searchResult.makeSnipets(issue.body, 40)) { snipets =>
-                        @if(snipets != null && snipets.size > 0) {
-                            <ul>
-                                @for(snipet <- snipets) {
-                                    <li>@snipet</li>
-                                }
-                            </ul>
-                        }
-                    }
-                </li>
-                }
-            </ul>
-            <!-- pagination.js will fill here. -->
-            <div id="pagination"></div>
-
-            <script type="text/javascript">
-                $(document).ready(function(){
-                    yobi.Pagination.update($("#pagination"), @page.getTotalPageCount);
-                });
-            </script>
-            }
+@if(project !=null) {
+    @projectLayout(message, project, utils.MenuType.NONE) {
+        @projectMenu(project, utils.MenuType.NONE, "main-menu-only")
+        @partial_search(group, project, searchResult)
+    }
+} else {
+    @if( group != null) {
+        @organizationLayout(message, utils.MenuType.NONE, group) {
+            @organization.header(group)
+            @organization.menu(group)
+            @partial_search(group, project, searchResult)
         }
-
-        @defining(searchResult.getUsers) { page =>
-            @if(page != null) {
-            <h4>Users</h4>
-            <ul>
-                @for(user <- page.getList) {
-                <li>@user.loginId @user.name</li>
-                }
-            </ul>
-            <!-- pagination.js will fill here. -->
-            <div id="pagination"></div>
-
-            <script type="text/javascript">
-                $(document).ready(function(){
-                    yobi.Pagination.update($("#pagination"), @page.getTotalPageCount);
-                });
-            </script>
-            }
+    } else {
+        @siteLayout(message, utils.MenuType.NONE) {
+            @partial_search(null, null, searchResult)
         }
-
-        @defining(searchResult.getProjects) { page =>
-            @if(page != null) {
-            <h4>Projects</h4>
-            <ul>
-                @for(project <- page.getList) {
-                <li>@project.owner/@project.name
-                    @defining(searchResult.makeSnipets(project.overview, 40)) { snipets =>
-                        @if(snipets != null && snipets.size > 0) {
-                            <ul>
-                                @for(snipet <- snipets) {
-                                    <li>@snipet</li>
-                                }
-                            </ul>
-                        }
-                    }
-                </li>
-                }
-            </ul>
-            <!-- pagination.js will fill here. -->
-            <div id="pagination"></div>
-
-            <script type="text/javascript">
-                $(document).ready(function(){
-                    yobi.Pagination.update($("#pagination"), @page.getTotalPageCount);
-                });
-            </script>
-            }
-        }
-
-        @defining(searchResult.getPosts) { page =>
-            @if(page != null) {
-            <h4>Issues</h4>
-            <ul>
-                @for(post <- page.getList) {
-                <li>@post.title
-                    @defining(searchResult.makeSnipets(post.body, 40)) { snipets =>
-                        @if(snipets != null && snipets.size > 0) {
-                            <ul>
-                                @for(snipet <- snipets) {
-                                    <li>@snipet</li>
-                                }
-                            </ul>
-                        }
-                    }
-                </li>
-                }
-            </ul>
-            <!-- pagination.js will fill here. -->
-            <div id="pagination"></div>
-
-            <script type="text/javascript">
-                $(document).ready(function(){
-                    yobi.Pagination.update($("#pagination"), @page.getTotalPageCount);
-                });
-            </script>
-            }
-        }
-
-        @defining(searchResult.getIssueComments) { page =>
-            @if(page != null) {
-            <h4>Issue Comments</h4>
-            <ul>
-                @for(comment <- page.getList) {
-                <li>@comment.authorName
-                    @defining(searchResult.makeSnipets(comment.contents, 40)) { snipets =>
-                        @if(snipets != null && snipets.size > 0) {
-                            <ul>
-                                @for(snipet <- snipets) {
-                                    <li>@snipet</li>
-                                }
-                            </ul>
-                        }
-                    }
-                </li>
-                }
-            </ul>
-            <!-- pagination.js will fill here. -->
-            <div id="pagination"></div>
-
-            <script type="text/javascript">
-                $(document).ready(function(){
-                    yobi.Pagination.update($("#pagination"), @page.getTotalPageCount);
-                });
-            </script>
-            }
-        }
-
-        @defining(searchResult.getPostComments) { page =>
-            @if(page != null) {
-            <h4>Post Comments</h4>
-            <ul>
-                @for(comment <- page.getList) {
-                <li>@comment.authorName
-                    @defining(searchResult.makeSnipets(comment.contents, 40)) { snipets =>
-                        @if(snipets != null && snipets.size > 0) {
-                            <ul>
-                                @for(snipet <- snipets) {
-                                    <li>@snipet</li>
-                                }
-                            </ul>
-                        }
-                    }
-                </li>
-                }
-            </ul>
-            <!-- pagination.js will fill here. -->
-            <div id="pagination"></div>
-
-            <script type="text/javascript">
-                $(document).ready(function(){
-                    yobi.Pagination.update($("#pagination"), @page.getTotalPageCount);
-                });
-            </script>
-            }
-        }
-
-        @defining(searchResult.getReviews) { page =>
-            @if(page != null) {
-            <h4>Reviews</h4>
-            <ul>
-                @for(review <- page.getList) {
-                <li>@review.author.name
-                    @defining(searchResult.makeSnipets(review.getContents, 40)) { snipets =>
-                        @if(snipets != null && snipets.size > 0) {
-                            <ul>
-                                @for(snipet <- snipets) {
-                                    <li>@snipet</li>
-                                }
-                            </ul>
-                        }
-                    }
-                </li>
-                }
-            </ul>
-            <!-- pagination.js will fill here. -->
-            <div id="pagination"></div>
-
-            <script type="text/javascript">
-                $(document).ready(function(){
-                    yobi.Pagination.update($("#pagination"), @page.getTotalPageCount);
-                });
-            </script>
-            }
-        }
-    </div>
-</div>
+    }
 }
app/views/siteLayout.scala.html
--- app/views/siteLayout.scala.html
+++ app/views/siteLayout.scala.html
@@ -23,7 +23,7 @@
 @import utils._
 
 @layout(Messages(title))(""){
-    @common.navbar(menuType, false)
+    @common.navbar(menuType, null, null)
 
     @if(menuType == utils.MenuType.SITE_HOME && UserApp.currentUser.isAnonymous){
         @index.partial_intro()
conf/messages
--- conf/messages
+++ conf/messages
@@ -657,6 +657,18 @@
 review.involvingYou = Reviews I have participated.
 review.is.empty = No review has been added.
 review.outdated = Outdated
+search.title = Search
+search.menu.boards = Posts
+search.menu.board.comments = Post Comments
+search.menu.issues = Issues
+search.menu.issue.comments = Issue Comments
+search.menu.milestones = milestones
+search.menu.projects = projects
+search.menu.reviews = Code Reviews
+search.menu.users =  Users
+search.scope.all = All Projects
+search.scope.group = This Group
+search.scope.porject = This Project
 site = Site
 site.features.codeManagement = Your code is safely stored in a version controlled system.
 site.features.codeReview = Review all changes in code with your team before merging. Code discussion will help you improve your code.
conf/messages.ko
--- conf/messages.ko
+++ conf/messages.ko
@@ -657,6 +657,18 @@
 review.involvingYou = 내가 참여한 리뷰
 review.is.empty = 등록된 리뷰가 없습니다.
 review.outdated = 만료
+search.title = 검색
+search.menu.boards = 게시판
+search.menu.board.comments = 게시판 댓글
+search.menu.issues = 이슈
+search.menu.issue.comments = 이슈 댓글
+search.menu.milestones = 마일스톤
+search.menu.projects = 프로젝트
+search.menu.reviews = 코드 리뷰
+search.menu.users =  사용자
+search.scope.all = 모든 프로젝트
+search.scope.group = 현재 그룹
+search.scope.porject = 현재 프로젝트
 site = 사이트
 site.features.codeManagement = 작성한 코드는 모두 이력이 관리되는 형태로 안전하게 서버에 보관됩니다.
 site.features.codeReview = 변경된 코드를 보면서 팀원들과 토론해보세요. 코드의 완성도를 더욱 높일 수 있습니다.
Add a comment
List