Add export and import and batch delete subscribers feature.
This commit is contained in:
parent
bb3236feba
commit
4735b107d7
|
@ -25,4 +25,87 @@ class Admin::EPaperSubscribersController < OrbitAdminController
|
|||
end
|
||||
redirect_to admin_e_paper_subscribers_path
|
||||
end
|
||||
|
||||
def export_excel
|
||||
@epaper_subscribers = EPaperSubscriber.where(:email.nin=>[nil,""]).desc(:created_at)
|
||||
@subscribers = @epaper_subscribers.where(:subscribed.ne=>false)
|
||||
@unsubscribers = @epaper_subscribers.where(:subscribed=>false)
|
||||
respond_to do |format|
|
||||
format.xlsx {
|
||||
response.headers['Content-Disposition'] = 'attachment; filename="'+Site.first.title+'-'+I18n.t('e_paper.e_paper')+'-'+I18n.t('e_paper.subscriber')+'.xlsx"'
|
||||
}
|
||||
end
|
||||
end
|
||||
def get_subscribers_modal
|
||||
@epaper_subscribers = EPaperSubscriber.where(:email.nin=>[nil,""]).desc(:created_at)
|
||||
@subscribers = @epaper_subscribers.where(:subscribed.ne=>false)
|
||||
@unsubscribers = @epaper_subscribers.where(:subscribed=>false)
|
||||
render :partial => 'modal_select', :layout => false
|
||||
end
|
||||
def import_from_excel
|
||||
workbook = RubyXL::Parser.parse(params["import_file"].tempfile)
|
||||
subscribe_sheet = workbook['Subscribe']
|
||||
unsubscribe_sheet = workbook['Unsubscribe']
|
||||
subscribe_sheet.each_with_index do |row, i|
|
||||
next if i < 1
|
||||
c0 = row.cells[0]
|
||||
c1 = row.cells[1]
|
||||
if c0
|
||||
email = c0.value
|
||||
if email.present?
|
||||
subscriber = EPaperSubscriber.where(:email=>email).first
|
||||
if subscriber.nil?
|
||||
subscriber = EPaperSubscriber.new(:email=>email)
|
||||
end
|
||||
language = c1.value
|
||||
if language.blank?
|
||||
language = I18n.locale.to_s
|
||||
end
|
||||
subscriber.subscribed = true
|
||||
subscriber.language = language
|
||||
subscriber.save
|
||||
end
|
||||
end
|
||||
end
|
||||
unsubscribe_sheet.each_with_index do |row, i|
|
||||
next if i < 1
|
||||
c0 = row.cells[0]
|
||||
c1 = row.cells[1]
|
||||
if c0
|
||||
email = c0.value
|
||||
if email.present?
|
||||
subscriber = EPaperSubscriber.where(:email=>email).first
|
||||
if subscriber.nil?
|
||||
subscriber = EPaperSubscriber.new(:email=>email)
|
||||
end
|
||||
language = c1.value
|
||||
if language.blank?
|
||||
language = I18n.locale.to_s
|
||||
end
|
||||
subscriber.subscribed = false
|
||||
subscriber.language = language
|
||||
subscriber.save
|
||||
end
|
||||
end
|
||||
end
|
||||
redirect_to admin_e_paper_subscribers_path
|
||||
end
|
||||
|
||||
def download_excel_format
|
||||
@subscribers = []
|
||||
@unsubscribers = []
|
||||
respond_to do |format|
|
||||
format.xlsx {
|
||||
response.headers['Content-Disposition'] = 'attachment; filename="'+Site.first.title+'-'+I18n.t('e_paper.e_paper')+'-'+I18n.t('e_paper.subscriber')+'excel_format.xlsx"'
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def delete_subscribers
|
||||
subscriber_ids = params['subscriber_ids']
|
||||
if subscriber_ids
|
||||
EPaperSubscriber.where(:id.in=>subscriber_ids).destroy
|
||||
end
|
||||
redirect_to admin_e_paper_subscribers_path
|
||||
end
|
||||
end
|
|
@ -269,6 +269,8 @@ class EPapersController < ApplicationController
|
|||
subscriber.subscribed = false
|
||||
subscriber.save
|
||||
data = {"success" => true, "msg" => "Successfully Unsubscribed!!!"}
|
||||
else
|
||||
data = {"success" => false, "msg" => "You are not a subscriber!!!"}
|
||||
end
|
||||
render :json => data.to_json
|
||||
end
|
||||
|
|
|
@ -28,5 +28,24 @@
|
|||
</tbody>
|
||||
</table>
|
||||
<div class="bottomnav clearfix" style="left: 81px;">
|
||||
<%= content_tag :div, paginate(@subscribers), class: "pagination pagination-centered" %>
|
||||
<%= content_tag(:div, paginate(@subscribers), class: "pagination pagination-centered") %>
|
||||
<div class="pull-right">
|
||||
<%=
|
||||
content_tag(:div, link_to(t("e_paper.export"), admin_e_paper_subscribers_export_excel_path + '.xlsx', :class=>"btn btn-success"), class: "pull-right")
|
||||
%>
|
||||
<div class="dropup upload-button pull-right">
|
||||
<button class="btn btn-info dropdown-toggle" type="button" data-toggle="dropdown">
|
||||
<i class="icon-upload-alt icon-white"></i><%= t('personal_journal.upload') %>
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<div class="dropdown-menu upload-box">
|
||||
<form action="<%=admin_e_paper_subscribers_import_from_excel_path%>" method="post" enctype="multipart/form-data">
|
||||
<%= hidden_field_tag :authenticity_token, form_authenticity_token %>
|
||||
<input type="file" name="import_file" >
|
||||
<button class="btn btn-primary" type="submit"><%= t(:submit) %></button>
|
||||
<a class="" href="<%=admin_e_paper_subscribers_download_excel_format_path%>.xlsx">Download excel format</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,202 @@
|
|||
<style>
|
||||
.checkbox-card .hide{
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
<div id="member-filter" class="modal hide fade" tabindex="-1" role="dialog" data-backdrop="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3><%= t('e_paper.subscribers') %></h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="tabbable tabs-left">
|
||||
<div class="nano">
|
||||
<div class="content">
|
||||
<ul class="nav nav-pills nav-stacked">
|
||||
<li class="active"><a href="#epaper_subscribed" data-toggle="tab">Subscribed</a></li>
|
||||
<li><a href="#epaper_unsubscribed" data-toggle="tab">Unsubscribed</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-content tab-content-1">
|
||||
<div class="tab-pane fade in active" id="epaper_subscribed">
|
||||
<div id="subscribers_form">
|
||||
<fieldset class="clearfix">
|
||||
<div class="member-filter-result nano">
|
||||
<div class="content">
|
||||
<i class="icon-search"></i>
|
||||
<input class="search_emails" placeholder="<%=t('email')%>" title="<%=t('email')%>">
|
||||
<div style="margin-bottom: 1em;"></div>
|
||||
<ul class="checkbox-card clearfix">
|
||||
<% @subscribers.each do |subscriber| %>
|
||||
<li class="check-item">
|
||||
<label class="checkbox inline">
|
||||
<span class="subscriber_email"><%= subscriber.email %></span>
|
||||
<%= check_box_tag 'subscriber_ids[]', subscriber.id, false , :id => "subscriber_ids_#{subscriber.id}" %>
|
||||
<%= hidden_field_tag 'subscriber_ids[]', subscriber.id %>
|
||||
</label>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<div class="form-actions">
|
||||
<div class="btn-group dropup" style="text-align:left;">
|
||||
<a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
|
||||
Select
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="#" class="select_all_modal"><i class="icon-ok"></i> Select All</a></li>
|
||||
<li><a href="#" class="deselect_all_modal"><i class="icon-remove"></i> De-select All</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<button type="button" class="btn" data-dismiss="modal"><%= t(:cancel) %></button>
|
||||
<%= submit_tag t(:confirm), class: "btn btn-primary" %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="epaper_unsubscribed">
|
||||
<div id="subscribers_form">
|
||||
<fieldset class="clearfix">
|
||||
<div class="member-filter-result nano">
|
||||
<div class="content">
|
||||
<i class="icon-search"></i>
|
||||
<input class="search_emails" placeholder="<%=t('email')%>" title="<%=t('email')%>">
|
||||
<div style="margin-bottom: 1em;"></div>
|
||||
<ul class="checkbox-card clearfix">
|
||||
<% @unsubscribers.each do |unsubscriber| %>
|
||||
<li class="check-item">
|
||||
<label class="checkbox inline">
|
||||
<span class="subscriber_email"><%= unsubscriber.email %></span>
|
||||
<%= check_box_tag 'subscriber_ids[]', unsubscriber.id, false , :id => "subscriber_ids_#{unsubscriber.id}" %>
|
||||
<%= hidden_field_tag 'subscriber_ids[]', unsubscriber.id %>
|
||||
</label>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<div class="form-actions">
|
||||
<div class="btn-group dropup" style="text-align:left;">
|
||||
<a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
|
||||
Select
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="#" class="select_all_modal"><i class="icon-ok"></i> Select All</a></li>
|
||||
<li><a href="#" class="deselect_all_modal"><i class="icon-remove"></i> De-select All</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<button type="button" class="btn" data-dismiss="modal"><%= t(:cancel) %></button>
|
||||
<%= submit_tag t(:confirm), class: "btn btn-primary" %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<style>
|
||||
.checkbox-card li .member-pic {
|
||||
float: left;
|
||||
margin-right: 5px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
$('#member-filter').on('show.bs.modal', function() {
|
||||
$('#member-filter').off('show.bs.modal');
|
||||
$(this).find('.nano').nanoScroller({ scrollTop: 0, iOSNativeScrolling: true });
|
||||
$(this).find('.checkbox-card').cardCheck();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
function encode_str(rawStr){
|
||||
var encodedStr = rawStr.replace(/[\u00A0-\u9999<>\&]/gim, function(i) {
|
||||
return '&#' + i.charCodeAt(0) + ';';
|
||||
});
|
||||
return encodedStr;
|
||||
}
|
||||
function generate_member_card(role_id,member_id,member_name,member_pic_url){
|
||||
return ('<li class="filter-item selected_item selected_member check-item" id="'+member_id+'">'+
|
||||
'<label>'+
|
||||
'<img alt="Member pic" class="member-pic" src="'+member_pic_url+'">'+
|
||||
'<span class="user-name" style="position: absolute;margin-left: 45px;">'+encode_str(member_name)+'</span>'+
|
||||
'</label>'+
|
||||
'<input name="<%=role_field_name rescue 'role_ids[]'%>" type="hidden" value='+role_id+'>'+
|
||||
'<input name="<%=member_field_name rescue 'member_ids[]'%>" type="hidden" value='+member_id+'>'+
|
||||
'<input type="checkbox">'+
|
||||
'</li>')
|
||||
};
|
||||
function generate_role_card(role_id,role_name,member_infos){
|
||||
if(member_infos.length == 0)
|
||||
return "";
|
||||
else{
|
||||
var member_cards = "";
|
||||
var fa = '<span style="top: 0.8em;position: absolute;right: 0.3em; font-family: FontAwesome;cursor: pointer;" class="fa fa-caret-down"></span>';
|
||||
member_infos.forEach(function(member_info){
|
||||
member_cards += generate_member_card(role_id,member_info.member_id,member_info.member_name,member_info.member_pic_url);
|
||||
});
|
||||
return ('<li class="selected_item selected_role role" id="'+role_id+'" style="height: unset;"><div class="selected">'+
|
||||
'<label>' +
|
||||
'<span class="role-name">' + role_name + '</span>'+
|
||||
'<span class="badge badge-info" style="position: absolute;right: 1.5em;">' + member_infos.length + '</span>' +
|
||||
'</label>' +
|
||||
'<input class="filter-checkbox" type="checkbox" style="width: calc(100% - 1.5em);height: 40px;">'+fa+
|
||||
'<ul class="sub-items">' +
|
||||
member_cards +
|
||||
'</ul></div>' +
|
||||
'</li>')
|
||||
};
|
||||
};
|
||||
function select_subscribers(){
|
||||
window.selected_subscriber_ids = [];
|
||||
var subscriber_cards = $('#member-filter [name="subscriber_ids[]"]:checked').map(function(i, subscriber){
|
||||
window.selected_subscriber_ids.push(subscriber.value);
|
||||
return $(subscriber).parent().parent().prop("outerHTML").replace('check-item active','check-item');
|
||||
}).toArray().join('');
|
||||
$('#members_field').html('<ul id="card-list-managers" class="checkbox-card clearfix">'+subscriber_cards+'</ul>');
|
||||
$('#members_field #card-list-managers .check-item').removeClass('hide');
|
||||
if(subscriber_cards != ""){
|
||||
$('#members_field').css('display','block');
|
||||
$('#edit_member_hint').css('display','none');
|
||||
}else{
|
||||
$('#members_field').css('display','none');
|
||||
$('#edit_member_hint').css('display','block');
|
||||
}
|
||||
$('#members_field').change();
|
||||
$("#member-filter").modal('hide');
|
||||
}
|
||||
$(document).ready(function(){
|
||||
$('#subscribers_form [type="submit"]').click(select_subscribers);
|
||||
if(window.selected_subscriber_ids){
|
||||
window.selected_subscriber_ids.forEach(function(v){
|
||||
var $v = $(`#member-filter input[value="${v}"]`);
|
||||
$v.prop("checked", true);
|
||||
$v.parent().parent().addClass('active');
|
||||
})
|
||||
}
|
||||
$('.search_emails').off('input').on('input',function(){
|
||||
var name = $(this).val();
|
||||
var $check_items = $(this).parent().find('.check-item');
|
||||
$check_items.each(function(i,item){
|
||||
if( $(item).find('.subscriber_email').text().search(name) == -1){
|
||||
$(item).addClass('hide');
|
||||
}else{
|
||||
$(item).removeClass('hide');
|
||||
}
|
||||
})
|
||||
})
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,339 @@
|
|||
<%= stylesheet_link_tag "member_select" %>
|
||||
<%= stylesheet_link_tag "lib/checkbox-card" %>
|
||||
<div class="mini-layout-body span10">
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane fade in active" id="subscribers_block">
|
||||
<div class="tab-pane-head">
|
||||
<h4><%= t('e_paper.batch_delete_subscribers') %></h4>
|
||||
</div>
|
||||
<ul id="card-list-members" class="checkbox-card clearfix">
|
||||
<fieldset style="background-color: white;border: 0.125em solid #666;font-family: cursive,serif;">
|
||||
<%= form_tag admin_e_paper_subscribers_delete_subscribers_path , :id=>'members_form' do %>
|
||||
<div id="members_field" style="display: none;margin-left: 1.5em;margin-left: 1.5em;"></div>
|
||||
<p id="edit_member_hint" aligin="center" style="font-size: 1.5em;padding: 2em;text-align: center;"><%= t("e_paper.delete_subscribers_hint") %></p>
|
||||
<input id="submit-type" name="type" type="hidden" value="">
|
||||
<% end %>
|
||||
</fieldset>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- footer -->
|
||||
<div class="bottomnav clearfix">
|
||||
<div class="action pull-right">
|
||||
<div class="btn-group dropup">
|
||||
<a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
|
||||
<%= t("select") %>
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="#" id="select_all"><i class="icon-ok"></i> <%= t("select_all") %></a></li>
|
||||
<li><a href="#" id="deselect_all"><i class="icon-remove"></i> <%= t("de_select_all") %></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<button class="btn btn-primary select_member_modal" href="#" type="button">
|
||||
<i class="icons-plus"></i>
|
||||
<%=t(:add)%>
|
||||
</button>
|
||||
<button class="btn" id="remove_subscribers" style="display: none;"><i class="icon-trash"></i> <%=t('site.edit_members.delete_from_choice') %></button>
|
||||
<button class="btn btn-danger" id="remove_subscribers_forever" style="display: none;"><i class="icon-trash"></i> <%=t('e_paper.delete_subscribers') %></button>
|
||||
<!-- <button class="btn" id="edit_members" style="display: none;"><i class="icon-trash"></i> <%=t('site.edit_members.edit_members') %></button> -->
|
||||
</div>
|
||||
</div>
|
||||
<% if @thread %>
|
||||
<div id="threadModal" class="modal hide fade in" tabindex="-1" role="dialog" aria-labelledby="threadModal" aria-hidden="false">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h3 id="threadModal"><%=t("site.edit_members.#{@thread.key}")%></h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<%= @thread.status[:finish_percent] %> % finished
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn" id="modal-close-btn" style="width: 4em;" data-dismiss="modal" aria-hidden="true"><%=t('close')%></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<div id='select_member_modal'></div>
|
||||
<script src="/assets/lib/jquery-ui-1.12.1/jquery-ui.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
/* 修正bootstap.js和jquery-ui.js間的衝突,使tab按鈕能正常運作 */
|
||||
var Button = function (element, options) {
|
||||
this.$element = $(element)
|
||||
this.options = $.extend({}, $.fn.button.defaults, options)
|
||||
}
|
||||
|
||||
Button.prototype.setState = function (state) {
|
||||
var d = 'disabled'
|
||||
, $el = this.$element
|
||||
, data = $el.data()
|
||||
, val = $el.is('input') ? 'val' : 'html'
|
||||
|
||||
state = state + 'Text'
|
||||
data.resetText || $el.data('resetText', $el[val]())
|
||||
|
||||
$el[val](data[state] || this.options[state])
|
||||
|
||||
// push to event loop to allow forms to submit
|
||||
setTimeout(function () {
|
||||
state == 'loadingText' ?
|
||||
$el.addClass(d).attr(d, d) :
|
||||
$el.removeClass(d).removeAttr(d)
|
||||
}, 0)
|
||||
}
|
||||
|
||||
Button.prototype.toggle = function () {
|
||||
var $parent = this.$element.closest('[data-toggle="buttons-radio"]')
|
||||
|
||||
$parent && $parent
|
||||
.find('.active')
|
||||
.removeClass('active')
|
||||
|
||||
this.$element.toggleClass('active')
|
||||
}
|
||||
|
||||
/* BUTTON PLUGIN DEFINITION
|
||||
* ======================== */
|
||||
|
||||
var old = $.fn.button
|
||||
|
||||
$.fn.button = function (option) {
|
||||
return this.each(function () {
|
||||
var $this = $(this)
|
||||
, data = $this.data('button')
|
||||
, options = typeof option == 'object' && option
|
||||
if (!data) $this.data('button', (data = new Button(this, options)))
|
||||
if (option == 'toggle') data.toggle()
|
||||
else if (option) data.setState(option)
|
||||
})
|
||||
}
|
||||
/* 修正bootstap.js和jquery-ui.js間的衝突,使tab按鈕能正常運作 */
|
||||
</script>
|
||||
<link rel="stylesheet" href="/assets/lib/jquery-ui-1.12.1/jquery-ui.min.css">
|
||||
<script type="text/javascript">
|
||||
if( Array.prototype.delete == undefined ){
|
||||
Array.prototype.delete = function(v){
|
||||
var idx = this.indexOf(v);
|
||||
if(idx != -1){
|
||||
return this.splice(idx, 1)[0];
|
||||
}else{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
function double_confirm_message(message){
|
||||
if(window.confirm(message)){
|
||||
if(window.confirm(message)){
|
||||
return true;
|
||||
}else{
|
||||
return false;
|
||||
};
|
||||
}else{
|
||||
return false;
|
||||
};
|
||||
};
|
||||
$(document).ready(function(){
|
||||
$(document).on('click','.modal-body .tab-content .check-item',function(){
|
||||
if($(this).hasClass("active"))
|
||||
$(this).removeClass("active");
|
||||
else
|
||||
$(this).addClass("active");
|
||||
});
|
||||
$(document).on('click',"#select_all",function(){
|
||||
$('#members_field').find(".check-item").addClass("active");
|
||||
$('#members_field').find(".check-item input[type=checkbox]").prop("checked","checked");
|
||||
$(".bottomnav .dropup").removeClass("open");
|
||||
if($('#members_field .filter-item').length != 0)
|
||||
$('#remove_subscribers').css('display','inline-block');
|
||||
return false;
|
||||
});
|
||||
$(document).on('click',"#deselect_all",function(){
|
||||
$('#members_field').find(".check-item").removeClass("active");
|
||||
$('#members_field').find(".check-item input[type=checkbox]").removeAttr("checked");
|
||||
$(".bottomnav .dropup").removeClass("open");
|
||||
$('#remove_subscribers').css('display','none');
|
||||
return false;
|
||||
});
|
||||
$(document).on('click',".select_all_modal",function(){
|
||||
$('#select_member_modal .tab-pane.active').find('.check-item:not(.hide)').addClass("active");
|
||||
$('#select_member_modal .tab-pane.active').find('.check-item:not(.hide) input[type=checkbox]').prop("checked","checked");
|
||||
$(".modal-body .dropup").removeClass("open");
|
||||
return false;
|
||||
});
|
||||
$(document).on('click',".deselect_all_modal",function(){
|
||||
$('#select_member_modal .tab-pane.active').find('.check-item:not(.hide)').removeClass("active");
|
||||
$('#select_member_modal .tab-pane.active').find('.check-item:not(.hide) input[type=checkbox]').prop("checked","");
|
||||
$(".modal-body .dropup").removeClass("open");
|
||||
return false;
|
||||
});
|
||||
$(document).on('click',".select_member_modal",function () {
|
||||
$.get("<%= admin_e_paper_subscribers_get_subscribers_modal_path %>").done(function(data){
|
||||
$("#select_member_modal").html(data);
|
||||
$("#member-filter").modal('show');
|
||||
});
|
||||
return false;
|
||||
});
|
||||
$('#remove_subscribers').click(function(){
|
||||
var $delete_items = $('#members_field .check-item.active');
|
||||
var delete_count = $delete_items.length;
|
||||
for(var i = 0;i < delete_count;i++){
|
||||
window.selected_subscriber_ids.delete($delete_items.eq(i).find('input').val());
|
||||
$delete_items.eq(i).remove();
|
||||
};
|
||||
if($('#members_field .check-item').length == 0)
|
||||
$('#edit_member_hint').css('display','block');
|
||||
$(this).css('display','none');
|
||||
if($('#members_field .check-item').length != 0){
|
||||
$('#remove_subscribers_forever').css('display','inline-block');
|
||||
$('#edit_members').css('display','inline-block');
|
||||
}else{
|
||||
$('#remove_subscribers_forever').css('display','none');
|
||||
$('#edit_members').css('display','none');
|
||||
};
|
||||
});
|
||||
$('#members_field').change(function(){
|
||||
if($('#members_field .check-item').length != 0){
|
||||
$('#remove_subscribers_forever').css('display','inline-block');
|
||||
$('#edit_members').css('display','inline-block');
|
||||
}else{
|
||||
$('#remove_subscribers_forever').css('display','none');
|
||||
$('#edit_members').css('display','none');
|
||||
};
|
||||
$('#members_field .check-item').off('click').on('click',function(){
|
||||
$el = $(this).parent().parent();
|
||||
if($el.hasClass("active")){
|
||||
$el.removeClass('active');
|
||||
if($('#members_field .check-item.active').length != 0)
|
||||
$('#remove_subscribers').css('display','inline-block');
|
||||
else
|
||||
$('#remove_subscribers').css('display','none');
|
||||
}else{
|
||||
$el.addClass('active');
|
||||
$('#remove_subscribers').css('display','inline-block');
|
||||
}
|
||||
return false;
|
||||
});
|
||||
$('#members_field .check-item').off('click').on('click',function(){
|
||||
if($(this).hasClass("active"))
|
||||
$(this).removeClass("active");
|
||||
else
|
||||
$(this).addClass("active");
|
||||
if($('#members_field .check-item.active').length != 0)
|
||||
$('#remove_subscribers').css('display','inline-block');
|
||||
else
|
||||
$('#remove_subscribers').css('display','none');
|
||||
return false;
|
||||
});
|
||||
$('.fa-caret-down').off('click').on('click',function(){
|
||||
if($(this).parent().hasClass('open'))
|
||||
$(this).parent().removeClass("open");
|
||||
else
|
||||
$(this).parent().addClass("open");
|
||||
})
|
||||
$('#remove_subscribers_forever').off('click').on('click',function(){
|
||||
var member_cards = '<ul id="card-list-managers" class="checkbox-card clearfix" style="clear: left;">'+$.map($('#members_field .check-item'),function(member_card,i){
|
||||
return member_card.outerHTML;
|
||||
}).join('')+'</ul>';
|
||||
if(double_confirm_message('<%= t('e_paper.delete_subscribers_hint') %>')){
|
||||
$("#members_form").before("<div id='dialog-confirm' title='"+"<%= t('site.edit_members.delete_hint1') %>'>"+
|
||||
"<div style='clear:both;'></div><div><span class='ui-icon ui-icon-alert' style='float:left; margin:0 7px 20px 0;'></span>"+
|
||||
"<%= t('e_paper.delete_subscribers_hint2') %>"+member_cards+"</div>"+
|
||||
"</div>");
|
||||
$( "#dialog-confirm" ).dialog({
|
||||
resizable: true,
|
||||
minHeight: 100,
|
||||
maxHeight: 400,
|
||||
modal: true,
|
||||
buttons: {
|
||||
"<%= t('site.edit_members.confirm') %>": function(){$('#submit-type').val('remove_subscribers_forever');$('#members_form').submit();$( this ).dialog( "close" );},
|
||||
"<%= t('site.edit_members.cancel') %>": function() {
|
||||
$( this ).dialog( "close" );
|
||||
$( this ).remove();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
$('#edit_members').off('click').on('click',function(){
|
||||
$('#submit-type').val('select_edit_members');
|
||||
$('#members_form').submit();
|
||||
});
|
||||
})
|
||||
function update_thread(){
|
||||
$.post("<%=admin_threads_get_status_path%>",{"id": "<%=params[:thread_id]%>"}).done(function(data){
|
||||
var finish_percent = data["finish_percent"];
|
||||
var is_finish = (data["status"] == "finish" || data["status"] == "error");
|
||||
if(finish_percent){
|
||||
$("#threadModal .modal-body").text(finish_percent + " % finished")
|
||||
}
|
||||
if(!is_finish){
|
||||
window.time_out_id = window.setTimeout(update_thread, 1000);
|
||||
}else{
|
||||
if(window.time_out_id)
|
||||
window.clearTimeout(window.time_out_id);
|
||||
window.setTimeout(function(){
|
||||
$("#threadModal").modal("hide");
|
||||
alert(data["status"]);
|
||||
}, 3000);
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
if($("#threadModal").length != 0){
|
||||
$("#threadModal").modal("show");
|
||||
window.time_out_id = window.setTimeout(update_thread, 1000);
|
||||
}
|
||||
$(document).on('click','.modal-backdrop',function(){
|
||||
$('.modal').modal('hide');
|
||||
})
|
||||
})
|
||||
</script>
|
||||
<style type="text/css">
|
||||
.checkbox-card li:focus-within span{
|
||||
color: white;
|
||||
}
|
||||
.fa-caret-down:before {
|
||||
content: "\f078";
|
||||
}
|
||||
.sub-items{
|
||||
display: none;
|
||||
}
|
||||
.open .sub-items{
|
||||
display: block;
|
||||
margin: 0 0.5em;
|
||||
}
|
||||
.selected_role .selected_member:hover{
|
||||
background-color: #cccccc;
|
||||
}
|
||||
.selected_role .selected_member{
|
||||
width: 100%;
|
||||
}
|
||||
li.selected_role:hover{
|
||||
background-color: #696969;
|
||||
}
|
||||
.selected:hover{
|
||||
background-color: #0088cc;
|
||||
}
|
||||
.selected{
|
||||
height: 40px;
|
||||
}
|
||||
#remove_subscribers{
|
||||
background: black;
|
||||
color: white;
|
||||
}
|
||||
#edit_members{
|
||||
background: green;
|
||||
color: white;
|
||||
}
|
||||
#members_field .checkbox-card li:hover label span.user-name {
|
||||
color: black;
|
||||
}
|
||||
#members_field .checkbox-card li:hover > label > span.user-name {
|
||||
color: white;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,25 @@
|
|||
# encoding: utf-8
|
||||
|
||||
wb = xlsx_package.workbook
|
||||
|
||||
wb.add_worksheet(name: "Subscribe") do |sheet|
|
||||
|
||||
heading = sheet.styles.add_style(:b => true, :locked => true)
|
||||
body = sheet.styles.add_style(:font_name => '微軟正黑體')
|
||||
row = []
|
||||
row << t('email')
|
||||
row << t('language') + " , ex: #{I18n.available_locales.map{|l| l.to_s}.join(', ')}"
|
||||
|
||||
sheet.add_row row, :style => heading
|
||||
end
|
||||
|
||||
wb.add_worksheet(name: "Unsubscribe") do |sheet|
|
||||
|
||||
heading = sheet.styles.add_style(:b => true, :locked => true)
|
||||
body = sheet.styles.add_style(:font_name => '微軟正黑體')
|
||||
row = []
|
||||
row << t('email')
|
||||
row << t('language') + " , ex: #{I18n.available_locales.map{|l| l.to_s}.join(', ')}"
|
||||
|
||||
sheet.add_row row, :style => heading
|
||||
end
|
|
@ -0,0 +1,39 @@
|
|||
# encoding: utf-8
|
||||
|
||||
wb = xlsx_package.workbook
|
||||
|
||||
wb.add_worksheet(name: "Subscribe") do |sheet|
|
||||
|
||||
heading = sheet.styles.add_style(:b => true, :locked => true)
|
||||
body = sheet.styles.add_style(:font_name => '微軟正黑體')
|
||||
row = []
|
||||
row << t('email')
|
||||
row << t('language')
|
||||
|
||||
sheet.add_row row, :style => heading
|
||||
|
||||
@subscribers.each do |subscriber|
|
||||
row = []
|
||||
row << subscriber.email
|
||||
row << subscriber.language
|
||||
sheet.add_row row, :style => body, :types => [:string,:string]
|
||||
end
|
||||
end
|
||||
|
||||
wb.add_worksheet(name: "Unsubscribe") do |sheet|
|
||||
|
||||
heading = sheet.styles.add_style(:b => true, :locked => true)
|
||||
body = sheet.styles.add_style(:font_name => '微軟正黑體')
|
||||
row = []
|
||||
row << t('email')
|
||||
row << t('language')
|
||||
|
||||
sheet.add_row row, :style => heading
|
||||
|
||||
@unsubscribers.each do |subscriber|
|
||||
row = []
|
||||
row << subscriber.email
|
||||
row << subscriber.language
|
||||
sheet.add_row row, :style => body, :types => [:string,:string]
|
||||
end
|
||||
end
|
|
@ -1,3 +1,53 @@
|
|||
<style>
|
||||
.pull-right .upload-box {
|
||||
background: #fff none repeat scroll 0 0;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 5px;
|
||||
box-sizing: border-box;
|
||||
height: 70px;
|
||||
left: auto;
|
||||
min-width: 350px;
|
||||
padding: 10px;
|
||||
position: absolute;
|
||||
right: -1px;
|
||||
top: -75px;
|
||||
z-index: 1000;
|
||||
}
|
||||
.dropup .dropdown-menu, .navbar-fixed-bottom .dropdown .dropdown-menu {
|
||||
top: auto;
|
||||
bottom: 100%;
|
||||
margin-bottom: 1px;
|
||||
}
|
||||
.open > .dropdown-menu {
|
||||
display: block;
|
||||
}
|
||||
.dropdown-menu {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
z-index: 1000;
|
||||
display: none;
|
||||
float: left;
|
||||
min-width: 160px;
|
||||
padding: 5px 0;
|
||||
margin: 2px 0 0;
|
||||
list-style: none;
|
||||
background-color: #ffffff;
|
||||
border: 1px solid #ccc;
|
||||
border: 1px solid rgba(0, 0, 0, 0.2);
|
||||
*border-right-width: 2px;
|
||||
*border-bottom-width: 2px;
|
||||
-webkit-border-radius: 6px;
|
||||
-moz-border-radius: 6px;
|
||||
border-radius: 6px;
|
||||
-webkit-box-shadow: 0 5px 10px rgb(0 0 0 / 20%);
|
||||
-moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
|
||||
box-shadow: 0 5px 10px rgb(0 0 0 / 20%);
|
||||
-webkit-background-clip: padding-box;
|
||||
-moz-background-clip: padding;
|
||||
background-clip: padding-box;
|
||||
}
|
||||
</style>
|
||||
<%= render_filter @filter_fields, "index_table" %>
|
||||
<div id="index_table">
|
||||
<%= render 'index'%>
|
||||
|
|
|
@ -1,7 +1,16 @@
|
|||
en:
|
||||
module_name:
|
||||
e_paper: "ePaper"
|
||||
restful_actions:
|
||||
batch_delete_subscribers: "Batch Delete Subscribers"
|
||||
e_paper:
|
||||
delete_subscribers_hint2: "Delete Subscribers below forever."
|
||||
delete_subscribers_hint1: "Do you realy want to delete Subscribers you added forever?"
|
||||
delete_subscribers_hint: "Click 『Add』 button to select Subscribers"
|
||||
delete_subscribers: "Delete Subscribers"
|
||||
batch_delete_subscribers: "Batch Delete Subscribers"
|
||||
import: "Import"
|
||||
export: "Export"
|
||||
get_invalid_emails: get invalid email
|
||||
get_failed_emails: get sended-failed emails
|
||||
e_paper: "ePaper"
|
||||
|
|
|
@ -1,7 +1,16 @@
|
|||
zh_tw:
|
||||
module_name:
|
||||
e_paper: 電子報
|
||||
restful_actions:
|
||||
batch_delete_subscribers: "批次刪除訂閱者"
|
||||
e_paper:
|
||||
delete_subscribers_hint2: "永久刪除以下訂閱者"
|
||||
delete_subscribers_hint1: "您確定真的要永久刪除所選的訂閱者嗎?"
|
||||
delete_subscribers_hint: "點選『新增』按鈕選擇訂閱者"
|
||||
delete_subscribers: "刪除訂閱者"
|
||||
batch_delete_subscribers: "批次刪除訂閱者"
|
||||
import: "匯入"
|
||||
export: "匯出"
|
||||
get_invalid_emails: 顯示格式錯誤的email
|
||||
get_failed_emails: 顯示寄送失敗的email
|
||||
e_paper: "電子報"
|
||||
|
|
|
@ -12,6 +12,12 @@ Rails.application.routes.draw do
|
|||
get "get_invalid_emails"
|
||||
end
|
||||
end
|
||||
get 'e_paper_subscribers/export_excel', to: 'e_paper_subscribers#export_excel'
|
||||
get 'e_paper_subscribers/download_excel_format', to: 'e_paper_subscribers#download_excel_format'
|
||||
post 'e_paper_subscribers/import_from_excel', to: 'e_paper_subscribers#import_from_excel'
|
||||
get 'e_paper_subscribers/get_subscribers_modal', to: 'e_paper_subscribers#get_subscribers_modal'
|
||||
get 'e_paper_subscribers/batch_delete_subscribers', to: 'e_paper_subscribers#batch_delete_subscribers'
|
||||
post 'e_paper_subscribers/delete_subscribers', to: 'e_paper_subscribers#delete_subscribers'
|
||||
resources :e_paper_subscribers
|
||||
resources :e_papers do
|
||||
member do
|
||||
|
|
|
@ -65,9 +65,14 @@ module EPaper
|
|||
:priority=>6,
|
||||
:active_for_action=>{'admin/e_paper_subscribers'=>'index'},
|
||||
:available_for => 'managers'
|
||||
context_link 'e_paper.batch_delete_subscribers',
|
||||
:link_path=>"admin_e_paper_subscribers_batch_delete_subscribers_path" ,
|
||||
:priority=>7,
|
||||
:active_for_action=>{'admin/e_paper_subscribers'=>'batch_delete_subscribers'},
|
||||
:available_for => 'managers'
|
||||
context_link 'e_paper.instructions',
|
||||
:link_path=>"instructions_admin_e_papers_path" ,
|
||||
:priority=>7,
|
||||
:priority=>8,
|
||||
:active_for_action=>{'admin/e_paper'=>'instructions'},
|
||||
:available_for => 'users'
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue