Commit 9e53bcc2 by tady

tag merge

parent 9f24b7b2
......@@ -17,3 +17,4 @@
//= require_tree ./lib
//= require_tree .
_.mixin(_.string.exports());
# set debug method to window
# usage:
# debug()(something)
# And url must include '#debug' hash.
window.debug = ->
if console? && console.debug? && location.hash is '#debug'
return console.log.bind(console)
......
# .mod-tag-tree-filterの入力文字列をもとにmod-tag-tree内のliをフィルタリング
$ ->
$('.mod-tag-tree').each ->
$root = $(this)
$root.find('.mod-tag-tree-filter').on 'change keyup', ->
$input = $(this)
if _.isEmpty($input.val())
$root.find('li').show()
return
$root.find('li a').each ->
$a = $(this)
# aタグに検索文字列が含まれれば表示
if _.str.include $a.text().toLowerCase(), $input.val().toLowerCase()
$a.parent('li').show()
else
$a.parent('li').hide()
ul.mod-tag-tree {
margin: 0;
padding: 0;
line-height: 1.5;
list-style: none;
a {
display: inline-block;
}
ul {
margin: 0;
padding: 0;
line-height: 1.5;
list-style: none;
margin-left: 1.5em;
}
li {
margin: 0 0 0 0.5em;
padding: 0;
border-left: 1px solid #999;
zoom: 1;
}
li:before {
margin-right: 0.5em;
border-bottom: 1px solid #999;
float: left;
width: 1em;
height: 0.75em;
overflow: hidden;
content: "";
}
li:last-child {
border: none;
}
li:last-child:before {
border-left: 1px solid #999;
}
.mod-tag-tree-filter {
}
}
......@@ -6,6 +6,16 @@ class TagsController < ApplicationController
@posts = @tag.posts
end
def merge_to
@tag = Tag.find_by(tag_params) or raise ActiveRecord::RecordNotFound
@merge_to_tag = Tag.find_by(name: params[:merge_to_name]) or raise ActiveRecord::RecordNotFound
@tag.move_all_posts_to!(@merge_to_tag)
@tag.delete
render json: { status: 'OK' }
end
private
def tag_params
......
module PostsHelper
# @param {ActiveRecord::Relation} node
def h_display_tree(node)
def h_display_tree_old(node)
_html = '<ul>'
if node.posts.count > 0
_html << %Q{<li><a href="#{ posts_path(q: '#' + node.name) }">#{node.name} <span class="badge">#{node.posts.count}</span></a></li>}
_html << %Q{
<li>
<a href="#{ posts_path(q: '#' + node.name) }">#{node.name} <span class="badge">#{node.posts.count}</span></a>
</li>
}
end
node.children.each do |_child|
_html << h_display_tree(_child)
end
_html << '</ul>'
_html.html_safe
end
# @param {ActiveRecord::Relation} node
def h_display_tree(node)
_html = ''
_html += %Q{
<a href="#{ posts_path(q: '#' + node.name) }" data-name="#{node.name}">
#{node.name} <span class="badge">#{node.posts.count}</span>
</a>
}
_html += '<ul>'
node.children.each do |_child|
_html += '<li>'
_html << h_display_tree(_child)
_html += '</li>'
end
_html << '</ul>'
......
......@@ -5,4 +5,12 @@ class Tag < ActiveRecord::Base
has_ancestry
default_scope { order(:updated_at => :desc) }
# 自分のタグに紐づくPostをすべて`other_tag`へ移動する
def move_all_posts_to!(other_tag)
self.posts.each do |_post|
_post.tags.delete(self)
_post.tags << other_tag unless _post.tags.include?(other_tag)
end
end
end
......@@ -25,7 +25,8 @@
</div><!--/.container-->
</div>
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.5.2/underscore-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.string/2.3.3/underscore.string.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="//netdna.bootstrapcdn.com/bootstrap/3.0.2/js/bootstrap.min.js"></script>
......
<%#
desc:
- appページの上部に
css:
- none
locals:
- none
usage:
render partial: 'partials/header_notifications'
%>
<% if flash[:success] %>
<div class="alert alert-success fade in">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
......
<%#
desc:
- タグTreeを表示
- フィルタリングフォームあり
css:
- mod-tag-tree.css
locals:
- root {Model}
usage:
render partial: 'partials/tag_tree', locals: { root: Tag }
%>
<ul class="mod-tag-tree">
<input type="search" class="mod-tag-tree-filter form-control" placeholder="filter...">
<% root.roots.each do |tag_root| %>
<li>
<%= h_display_tree(tag_root) %>
</li>
<% end %>
</ul>
......@@ -91,6 +91,7 @@
Launch demo modal
</button>
-->
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
......
<div class="row">
<div class="col-xs-8">
<h1><%= @tag.name %>についてのページ</h1>
</div>
<div class="col-xs-4">
<div class="btn-group pull-right">
<a class="btn btn-primary" href="#">
このページを編集する <span class="glyphicon glyphicon-pencil"></span>
</a>
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
<span class="caret"></span>
<span class="sr-only">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu" role="menu">
<li><a href="#" data-toggle="modal" data-target="#modal-merge">Merge to...</a></li>
<li><a href="#" data-toggle="modal" data-target="#myModal">Rename to...</a></li>
<li><a href="#" data-toggle="modal" data-target="#myModal">Open Tag Tree editor...</a></li>
</ul>
</div>
</div>
<div class="col-xs-8">
<div class="panel panel-default">
......@@ -23,3 +42,60 @@
</div>
</div><!--/row-->
<!-- Modal -->
<div class="modal fade" id="modal-merge" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<%= form_tag '#', method: :post, class: 'form-horizontal', role: 'form' do %>
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h3 class="modal-title" id="myModalLabel">Merge to other tag</h4>
</div>
<div class="modal-body">
<h4>マージ先のTagを選んでください</h4>
<div id="merge-tag-tree">
<%= render partial: 'partials/tag_tree', locals: { root: Tag } %>
</div>
</div>
<% content_for :footer_js do %>
<script type="text/javascript">
$(function(){
$('#merge-tag-tree a').on('click', function(e){
console.log(e)
e.preventDefault();
var $this = $(this);
if(window.confirm('「<%= @tag.name %>」を「' + $this.data('name') + '」にマージます')) {
$.ajax({
type: "POST",
url: "/tags/<%= @tag.name %>/merge_to/" + $this.data('name')
}).done(function(data){
location.href = "/tags/" + $this.data('name');
}).fail(function(data){
alert('error');
});
} else {
return false;
}
})
})
</script>
<% end %>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div><!-- /.modal-content -->
<% end %><%# form %>
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
......@@ -11,6 +11,7 @@ Rendezvous::Application.routes.draw do
resources :posts
get 'tags/:name' => 'tags#show', as: 'show_tag'
post 'tags/:name/merge_to/:merge_to_name' => 'tags#merge_to', as: 'merge_to_tag'
devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks' }
......
......@@ -4,4 +4,8 @@ FactoryGirl.define do
factory :tag_ruby, class: Tag do
name 'ruby'
end
factory :tag_java, class: Tag do
name 'java'
end
end
require 'spec_helper'
describe Tag do
pending "add some examples to (or delete) #{__FILE__}"
describe '#move_posts_to' do
before :each do
@tag_ruby = Tag.create(name: 'ruby')
@tag_java = Tag.create(name: 'java')
@post1 = Post.create id: 1001, title: 'ruby rspec', tags: [@tag_ruby]
@post2 = Post.create id: 1002, title: 'ruby is better than java', tags: [@tag_ruby, @tag_java]
@post3 = Post.create id: 1003, title: 'java java...', tags: [@tag_java]
end
it 'successfully moved' do
expect(Tag.find_by(name: 'ruby').posts).to have(2).items
expect(Tag.find_by(name: 'java').posts).to have(2).items
@tag_java.move_all_posts_to!(@tag_ruby)
expect(Tag.find_by(name: 'ruby').posts).to have(3).items
expect(Tag.find_by(name: 'java').posts).to have(0).items
end
end
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment