Add manual RSS/JSON subscription with configurable field mapping
This commit is contained in:
parent
786954e35b
commit
d981c38f72
|
|
@ -12,6 +12,206 @@
|
|||
$("#site-url-wrapper").fadeOut();
|
||||
getChannelList();
|
||||
})
|
||||
$("#toggle-manual-rss").on("click",function(){
|
||||
$("#manual-rss-form").slideToggle();
|
||||
})
|
||||
$("input[name='source-type']").on("change",function(){
|
||||
if($(this).val() == "json"){
|
||||
$("#rss-detect-block").hide();
|
||||
$("#json-detect-block").show();
|
||||
}else{
|
||||
$("#json-detect-block").hide();
|
||||
$("#rss-detect-block").show();
|
||||
}
|
||||
})
|
||||
|
||||
$("#manual-rss-detect").on("click",function(){
|
||||
var rss_url = $("#manual-rss-url").val().trim();
|
||||
if(!rss_url){
|
||||
alert("請先填寫 RSS 網址");
|
||||
return;
|
||||
}
|
||||
$.ajax({
|
||||
url: "/admin/feeds/rss_fields",
|
||||
data: {"url": rss_url},
|
||||
dataType: "json",
|
||||
type: "get"
|
||||
}).done(function(data){
|
||||
if(!data.fields || data.fields.length == 0){
|
||||
alert("偵測不到欄位,請確認 RSS 網址是否正確");
|
||||
return;
|
||||
}
|
||||
var titleSelect = $("#manual-rss-title-field");
|
||||
var linkSelect = $("#manual-rss-link-field");
|
||||
var imageSelect = $("#manual-rss-image-field");
|
||||
titleSelect.html("");
|
||||
linkSelect.html("");
|
||||
imageSelect.html("<option value=''>(不設定圖片欄位)</option>");
|
||||
$.each(data.fields, function(i, f){
|
||||
titleSelect.append("<option value='" + f + "'" + (f=="title" ? " selected" : "") + ">" + f + "</option>");
|
||||
linkSelect.append("<option value='" + f + "'" + (f=="link" ? " selected" : "") + ">" + f + "</option>");
|
||||
imageSelect.append("<option value='" + f + "'" + (f=="imageUrl" ? " selected" : "") + ">" + f + "</option>");
|
||||
})
|
||||
$("#manual-rss-mapping").show();
|
||||
})
|
||||
})
|
||||
|
||||
$("#json-detect-step1").on("click",function(){
|
||||
var json_url = $("#manual-rss-url").val().trim();
|
||||
if(!json_url){
|
||||
alert("請先填寫網址");
|
||||
return;
|
||||
}
|
||||
$.ajax({
|
||||
url: "/admin/feeds/json_top_keys",
|
||||
data: {"url": json_url},
|
||||
dataType: "json",
|
||||
type: "get"
|
||||
}).done(function(data){
|
||||
if(data.error){
|
||||
alert("抓取失敗,請確認網址是否正確、是否為 JSON 格式");
|
||||
return;
|
||||
}
|
||||
var select = $("#json-list-key-select");
|
||||
select.html("");
|
||||
if(data.root_is_array){
|
||||
select.append("<option value=''>(根層級本身就是陣列)</option>");
|
||||
}
|
||||
$.each(data.array_keys, function(i, k){
|
||||
select.append("<option value='" + k + "'>" + k + "</option>");
|
||||
})
|
||||
if(!data.root_is_array && data.array_keys.length == 0){
|
||||
alert("偵測不到任何陣列欄位,請確認這個網址回傳的是不是文章列表 JSON");
|
||||
return;
|
||||
}
|
||||
$("#json-list-key-wrapper").show();
|
||||
$("#json-field-mapping").hide();
|
||||
})
|
||||
})
|
||||
|
||||
$("#json-detect-step2").on("click",function(){
|
||||
var json_url = $("#manual-rss-url").val().trim();
|
||||
var list_key = $("#json-list-key-select").val();
|
||||
$.ajax({
|
||||
url: "/admin/feeds/json_item_fields",
|
||||
data: {"url": json_url, "list_key": list_key},
|
||||
dataType: "json",
|
||||
type: "get"
|
||||
}).done(function(data){
|
||||
if(!data.fields || data.fields.length == 0){
|
||||
alert("偵測不到欄位,請確認列表位置選對了嗎");
|
||||
return;
|
||||
}
|
||||
var titleSelect = $("#json-title-field");
|
||||
var subtitleSelect = $("#json-subtitle-field");
|
||||
var contentSelect = $("#json-content-field");
|
||||
var timeSelect = $("#json-time-field");
|
||||
var imageSelect = $("#json-image-field");
|
||||
var idSelect = $("#json-id-field");
|
||||
var linkFieldSelect = $("#json-link-field");
|
||||
titleSelect.html("");
|
||||
subtitleSelect.html("<option value=''>(不設定副標題欄位)</option>");
|
||||
contentSelect.html("<option value=''>(不設定內容欄位)</option>");
|
||||
timeSelect.html("");
|
||||
imageSelect.html("<option value=''>(不設定圖片欄位)</option>");
|
||||
idSelect.html("");
|
||||
linkFieldSelect.html("");
|
||||
$.each(data.fields, function(i, f){
|
||||
titleSelect.append("<option value='" + f + "'>" + f + "</option>");
|
||||
subtitleSelect.append("<option value='" + f + "'>" + f + "</option>");
|
||||
contentSelect.append("<option value='" + f + "'>" + f + "</option>");
|
||||
timeSelect.append("<option value='" + f + "'>" + f + "</option>");
|
||||
imageSelect.append("<option value='" + f + "'>" + f + "</option>");
|
||||
idSelect.append("<option value='" + f + "'>" + f + "</option>");
|
||||
linkFieldSelect.append("<option value='" + f + "'" + ((f=="url"||f=="link") ? " selected" : "") + ">" + f + "</option>");
|
||||
})
|
||||
$("#json-field-mapping").show();
|
||||
})
|
||||
})
|
||||
|
||||
$("input[name='json-link-mode']").on("change",function(){
|
||||
if($(this).val() == "template"){
|
||||
$("#json-link-field-wrapper").hide();
|
||||
$("#json-link-template-wrapper").show();
|
||||
}else{
|
||||
$("#json-link-template-wrapper").hide();
|
||||
$("#json-link-field-wrapper").show();
|
||||
}
|
||||
})
|
||||
|
||||
$("#manual-rss-next").on("click",function(){
|
||||
var rss_url = $("#manual-rss-url").val().trim();
|
||||
var title = $("#manual-rss-title").val().trim();
|
||||
var source_type = $("input[name='source-type']:checked").val();
|
||||
var channel_key = "announcement";
|
||||
|
||||
if(!rss_url || !title){
|
||||
alert("請把網址、頻道顯示名稱填寫完整");
|
||||
return;
|
||||
}
|
||||
|
||||
site_url = rss_url;
|
||||
var title_translations = {};
|
||||
title_translations[I18n.locale] = title;
|
||||
var feed = {
|
||||
uid: title.replace(/\s+/g,'_') + "_" + Date.now(),
|
||||
url: rss_url,
|
||||
title_translations: title_translations
|
||||
};
|
||||
|
||||
if(source_type == "json"){
|
||||
var list_key = $("#json-list-key-select").val();
|
||||
var json_title_field = $("#json-title-field").val();
|
||||
var json_subtitle_field = $("#json-subtitle-field").val();
|
||||
var json_content_field = $("#json-content-field").val();
|
||||
var json_time_field = $("#json-time-field").val();
|
||||
var json_image_field = $("#json-image-field").val();
|
||||
var json_id_field = $("#json-id-field").val();
|
||||
var json_link_mode = $("input[name='json-link-mode']:checked").val();
|
||||
var json_link_field = $("#json-link-field").val();
|
||||
var json_link_template = $("#json-link-template").val().trim();
|
||||
|
||||
if(!json_title_field || !json_id_field){
|
||||
alert("請完成 JSON 欄位偵測,並至少填寫標題欄位、ID欄位");
|
||||
return;
|
||||
}
|
||||
if(json_link_mode == "template" && !json_link_template){
|
||||
alert("請填寫連結樣板");
|
||||
return;
|
||||
}
|
||||
if(json_link_mode == "field" && !json_link_field){
|
||||
alert("請選擇連結欄位");
|
||||
return;
|
||||
}
|
||||
|
||||
feed.is_json_list = true;
|
||||
feed.json_list_key = list_key;
|
||||
feed.json_id_field = json_id_field;
|
||||
feed.json_title_field = json_title_field;
|
||||
feed.json_subtitle_field = json_subtitle_field;
|
||||
feed.json_content_field = json_content_field;
|
||||
feed.json_time_field = json_time_field;
|
||||
feed.json_image_field = json_image_field;
|
||||
feed.json_link_mode = json_link_mode;
|
||||
feed.json_link_field = json_link_field;
|
||||
feed.json_link_template = json_link_template;
|
||||
}else{
|
||||
var title_field = $("#manual-rss-title-field").val();
|
||||
var link_field = $("#manual-rss-link-field").val();
|
||||
var image_field = $("#manual-rss-image-field").val();
|
||||
if(!title_field || !link_field){
|
||||
alert("請把標題欄位、連結欄位填寫完整");
|
||||
return;
|
||||
}
|
||||
feed.is_rss = true;
|
||||
feed.rss_title_field = title_field;
|
||||
feed.rss_link_field = link_field;
|
||||
feed.rss_image_field = image_field;
|
||||
}
|
||||
|
||||
var channel = {key: channel_key, title: title};
|
||||
subscribeFeed($("<div></div>"), feed, channel);
|
||||
})
|
||||
}
|
||||
|
||||
var getChannelList = function(){
|
||||
|
|
|
|||
|
|
@ -106,3 +106,15 @@
|
|||
margin-right: 10px;
|
||||
vertical-align: top;
|
||||
}
|
||||
#manual-rss-wrapper{
|
||||
width: 700px;
|
||||
margin: 10px auto 0;
|
||||
text-align: center;
|
||||
}
|
||||
#manual-rss-form{
|
||||
margin-top: 8px;
|
||||
}
|
||||
.manual-rss-input{
|
||||
width: 680px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -161,6 +161,54 @@ class Admin::FeedsController < OrbitAdminController
|
|||
end
|
||||
render :json => data.to_json
|
||||
end
|
||||
|
||||
def rss_fields
|
||||
fields = []
|
||||
begin
|
||||
uri = URI(params[:url])
|
||||
body = http_request(uri).body
|
||||
rss_data = Hash.from_xml(body)
|
||||
items = rss_data['rss']['channel']['item']
|
||||
first_item = items.is_a?(Array) ? items.first : items
|
||||
fields = first_item.keys if first_item.is_a?(Hash)
|
||||
rescue => e
|
||||
fields = []
|
||||
end
|
||||
render :json => {"fields" => fields}.to_json
|
||||
end
|
||||
|
||||
def json_top_keys
|
||||
data = {}
|
||||
begin
|
||||
uri = URI(params[:url])
|
||||
body = http_request(uri).body
|
||||
json_data = JSON.parse(body)
|
||||
if json_data.is_a?(Array)
|
||||
data = {"root_is_array" => true, "array_keys" => []}
|
||||
else
|
||||
array_keys = json_data.select{|k,v| v.is_a?(Array)}.keys
|
||||
data = {"root_is_array" => false, "array_keys" => array_keys}
|
||||
end
|
||||
rescue => e
|
||||
data = {"error" => true}
|
||||
end
|
||||
render :json => data.to_json
|
||||
end
|
||||
|
||||
def json_item_fields
|
||||
fields = []
|
||||
begin
|
||||
uri = URI(params[:url])
|
||||
body = http_request(uri).body
|
||||
json_data = JSON.parse(body)
|
||||
items = SiteFeed.dig_by_path(json_data, params[:list_key])
|
||||
first_item = Array(items).first
|
||||
fields = first_item.keys if first_item.is_a?(Hash)
|
||||
rescue => e
|
||||
fields = []
|
||||
end
|
||||
render :json => {"fields" => fields}.to_json
|
||||
end
|
||||
|
||||
def get_feed_list
|
||||
data_to_send = {}
|
||||
|
|
@ -217,10 +265,32 @@ class Admin::FeedsController < OrbitAdminController
|
|||
site_feed.feed_name_translations = params[:feed][:title_translations]
|
||||
site_feed.disabled = false
|
||||
site_feed.feed_url = params[:feed][:url]
|
||||
if params[:feed][:is_rss]
|
||||
if params[:feed][:is_rss]
|
||||
site_feed.is_rss = params[:feed][:is_rss]
|
||||
end
|
||||
uri = URI(site_feed.remote_site_url)
|
||||
if params[:feed][:rss_title_field].present?
|
||||
site_feed.rss_title_field = params[:feed][:rss_title_field]
|
||||
end
|
||||
if params[:feed][:rss_link_field].present?
|
||||
site_feed.rss_link_field = params[:feed][:rss_link_field]
|
||||
end
|
||||
if params[:feed][:rss_image_field].present?
|
||||
site_feed.rss_image_field = params[:feed][:rss_image_field]
|
||||
end
|
||||
if params[:feed][:is_json_list]
|
||||
site_feed.is_json_list = params[:feed][:is_json_list]
|
||||
site_feed.json_list_key = params[:feed][:json_list_key]
|
||||
site_feed.json_id_field = params[:feed][:json_id_field]
|
||||
site_feed.json_title_field = params[:feed][:json_title_field]
|
||||
site_feed.json_subtitle_field = params[:feed][:json_subtitle_field]
|
||||
site_feed.json_content_field = params[:feed][:json_content_field]
|
||||
site_feed.json_time_field = params[:feed][:json_time_field]
|
||||
site_feed.json_image_field = params[:feed][:json_image_field]
|
||||
site_feed.json_link_mode = params[:feed][:json_link_mode]
|
||||
site_feed.json_link_field = params[:feed][:json_link_field]
|
||||
site_feed.json_link_template = params[:feed][:json_link_template]
|
||||
end
|
||||
uri = URI(site_feed.remote_site_url)
|
||||
site_host = uri.host
|
||||
other_site_feeds = SiteFeed.where(:remote_site_url=>/:\/\/#{::Regexp.escape(site_host)}/)
|
||||
other_site_feed = other_site_feeds.first
|
||||
|
|
|
|||
|
|
@ -20,6 +20,20 @@ class SiteFeed
|
|||
field :feeds_update_statuses_callback
|
||||
field :enable_notify, type: Boolean, default: false
|
||||
field :is_rss, type: Boolean, default: false
|
||||
field :rss_title_field, default: "title"
|
||||
field :rss_link_field, default: "link"
|
||||
field :rss_image_field
|
||||
field :is_json_list, type: Boolean, default: false
|
||||
field :json_list_key
|
||||
field :json_id_field
|
||||
field :json_title_field
|
||||
field :json_subtitle_field
|
||||
field :json_content_field
|
||||
field :json_time_field
|
||||
field :json_image_field
|
||||
field :json_link_mode, default: "field"
|
||||
field :json_link_field
|
||||
field :json_link_template
|
||||
require 'fileutils'
|
||||
include Feeds::Cache
|
||||
Category.send(:include,Feeds::Cache)
|
||||
|
|
@ -103,15 +117,20 @@ class SiteFeed
|
|||
rss_data = Hash.from_xml(res)
|
||||
category_title = rss_data['rss']['channel']['title']
|
||||
category_title_trans = to_I18n(category_title, true)
|
||||
title_field = self.rss_title_field.presence || "title"
|
||||
link_field = self.rss_link_field.presence || "link"
|
||||
image_field = self.rss_image_field
|
||||
res_to_json = rss_data['rss']['channel']["item"].collect do |item|
|
||||
tag_titles = Array(item['類別']).collect{|title| to_I18n(title, true, "name_translations")}
|
||||
id = item['link'].split("&s=")[-1]
|
||||
title = Array(item['title'])[0]
|
||||
item_link = item[link_field]
|
||||
id = item_link.split("&s=")[-1]
|
||||
title = Array(item[title_field])[0]
|
||||
text = Array(item['description'])[0]
|
||||
image_url = image_field.present? ? item[image_field] : nil
|
||||
files = []
|
||||
if text.include?('附件')
|
||||
files = Nokogiri::HTML(get_response_body(URI(item['link']))).search('#RelData1_liFile ol a').collect do |v|
|
||||
file_title = v.attr('title')
|
||||
files = Nokogiri::HTML(get_response_body(URI(item_link))).search('#RelData1_liFile ol a').collect do |v|
|
||||
file_title = v.attr('title')
|
||||
{
|
||||
"description_translations" => to_I18n(file_title),
|
||||
"title_translations" => to_I18n(file_title.sub(/^\[(?:(?!\]).)*\]/,'').rpartition(".")[0]),
|
||||
|
|
@ -128,7 +147,11 @@ class SiteFeed
|
|||
"text_translations" => to_I18n(text),
|
||||
"postdate" => DateTime.parse(item['pubDate']).to_s,
|
||||
"image_description_translations" => {},
|
||||
"image" => {},
|
||||
"image" => image_url.blank? ? {} : {
|
||||
"thumb" => image_url,
|
||||
"mobile" => image_url,
|
||||
"original" => image_url
|
||||
},
|
||||
"display_img" => false,
|
||||
"tags" => tag_titles,
|
||||
"category" => category_title_trans,
|
||||
|
|
@ -137,7 +160,57 @@ class SiteFeed
|
|||
"bulletin_links" => [],
|
||||
"bulletin_files" => files,
|
||||
"bulletin_carousel_images" => [],
|
||||
"external_link" => nil
|
||||
"external_link" => item_link
|
||||
}
|
||||
end
|
||||
res = JSON.dump({"announcements" => res_to_json})
|
||||
elsif self.is_json_list
|
||||
json_data = JSON.parse(res) rescue {}
|
||||
items = self.class.dig_by_path(json_data, self.json_list_key)
|
||||
id_field = self.json_id_field
|
||||
title_field = self.json_title_field
|
||||
subtitle_field = self.json_subtitle_field
|
||||
content_field = self.json_content_field
|
||||
time_field = self.json_time_field
|
||||
image_field = self.json_image_field
|
||||
link_mode = self.json_link_mode.presence || "field"
|
||||
link_field = self.json_link_field
|
||||
link_template = self.json_link_template
|
||||
res_to_json = Array(items).collect do |item|
|
||||
id = id_field.present? ? item[id_field].to_s : nil
|
||||
if link_mode == "template"
|
||||
link = (link_template.present? && id.present?) ? link_template.gsub("{id}", id) : nil
|
||||
else
|
||||
link = link_field.present? ? item[link_field] : nil
|
||||
end
|
||||
title = title_field.present? ? item[title_field] : nil
|
||||
subtitle = subtitle_field.present? ? item[subtitle_field] : nil
|
||||
content = content_field.present? ? item[content_field] : nil
|
||||
postdate = (time_field.present? ? (DateTime.parse(item[time_field]) rescue DateTime.now) : DateTime.now).to_s
|
||||
image_url = image_field.present? ? item[image_field] : nil
|
||||
{
|
||||
"show_url" => link,
|
||||
"org_is_top" => 0,
|
||||
"id" => id,
|
||||
"title_translations" => to_I18n(title),
|
||||
"subtitle_translations" => to_I18n(subtitle),
|
||||
"text_translations" => to_I18n(content),
|
||||
"postdate" => postdate,
|
||||
"image_description_translations" => {},
|
||||
"image" => image_url.blank? ? {} : {
|
||||
"thumb" => image_url,
|
||||
"mobile" => image_url,
|
||||
"original" => image_url
|
||||
},
|
||||
"display_img" => !image_url.blank?,
|
||||
"tags" => [],
|
||||
"category" => category_title_trans,
|
||||
"author" => nil,
|
||||
"params" => "#{title}-#{id}",
|
||||
"bulletin_links" => [],
|
||||
"bulletin_files" => [],
|
||||
"bulletin_carousel_images" => [],
|
||||
"external_link" => link
|
||||
}
|
||||
end
|
||||
res = JSON.dump({"announcements" => res_to_json})
|
||||
|
|
@ -151,6 +224,12 @@ class SiteFeed
|
|||
end
|
||||
anns
|
||||
end
|
||||
|
||||
def self.dig_by_path(data, path)
|
||||
return data if path.blank?
|
||||
path.split(".").inject(data) { |acc, key| acc.is_a?(Hash) ? acc[key] : nil }
|
||||
end
|
||||
|
||||
def get_response_body(uri)
|
||||
res = Net::HTTP.start(uri.host, uri.port,
|
||||
:use_ssl => uri.scheme == 'https',
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
<div id="import-container">
|
||||
<div id="import-head" class="muted">
|
||||
<i class='icons-rss'></i><br/>
|
||||
Subscribe to channels
|
||||
Subscribe to Orbit channels
|
||||
</div>
|
||||
|
||||
<div id="loading" style="display:none;">
|
||||
|
|
@ -16,10 +16,73 @@
|
|||
</div>
|
||||
|
||||
<div id="site-url-wrapper" class="import-wrapper">
|
||||
<input type="text" class="import-url" name="url" value="" placeholder="http://www.rulingcom.com">
|
||||
<input type="text" class="import-url" name="url" value="" placeholder="http://orbitek.co">
|
||||
<button id="find-channels" class="btn btn-primary">Find Channels</button>
|
||||
</div>
|
||||
|
||||
<!-- === 新增區塊:手動輸入 RSS 網址訂閱公告 === -->
|
||||
<div id="manual-rss-wrapper" class="import-wrapper">
|
||||
<a href="javascript:void(0);" id="toggle-manual-rss">或者,直接輸入網址訂閱公告</a>
|
||||
<div id="manual-rss-form" style="display:none;">
|
||||
|
||||
<div id="manual-source-type">
|
||||
<label><input type="radio" name="source-type" value="rss" checked> RSS 來源</label>
|
||||
|
||||
<label><input type="radio" name="source-type" value="json"> JSON API 來源</label>
|
||||
</div>
|
||||
<input type="text" id="manual-rss-url" class="manual-rss-input" placeholder="網址,例如 https://www.peopo.org/rss-top10"><br/>
|
||||
|
||||
<!-- RSS 偵測區塊 -->
|
||||
<div id="rss-detect-block">
|
||||
<button id="manual-rss-detect" class="btn">偵測欄位</button><br/>
|
||||
<div id="manual-rss-mapping" style="display:none;">
|
||||
標題欄位:<select id="manual-rss-title-field" class="manual-rss-input"></select><br/>
|
||||
連結欄位:<select id="manual-rss-link-field" class="manual-rss-input"></select><br/>
|
||||
圖片欄位:<select id="manual-rss-image-field" class="manual-rss-input">
|
||||
<option value="">(不設定圖片欄位)</option>
|
||||
</select><br/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- JSON 偵測區塊(新增) -->
|
||||
<div id="json-detect-block" style="display:none;">
|
||||
<button id="json-detect-step1" class="btn">第一步:抓取結構</button><br/>
|
||||
<div id="json-list-key-wrapper" style="display:none;">
|
||||
文章列表位置:<select id="json-list-key-select" class="manual-rss-input"></select>
|
||||
<button id="json-detect-step2" class="btn">第二步:抓取欄位</button><br/>
|
||||
</div>
|
||||
<div id="json-field-mapping" style="display:none;">
|
||||
標題欄位:<select id="json-title-field" class="manual-rss-input"></select><br/>
|
||||
副標題欄位:<select id="json-subtitle-field" class="manual-rss-input">
|
||||
<option value="">(不設定副標題欄位)</option>
|
||||
</select><br/>
|
||||
內容欄位:<select id="json-content-field" class="manual-rss-input">
|
||||
<option value="">(不設定內容欄位)</option>
|
||||
</select><br/>
|
||||
時間欄位:<select id="json-time-field" class="manual-rss-input"></select><br/>
|
||||
圖片欄位:<select id="json-image-field" class="manual-rss-input">
|
||||
<option value="">(不設定圖片欄位)</option>
|
||||
</select><br/>
|
||||
ID欄位:<select id="json-id-field" class="manual-rss-input"></select><br/>
|
||||
|
||||
連結來源:
|
||||
<label><input type="radio" name="json-link-mode" value="field" checked> 直接讀取欄位</label>
|
||||
<label><input type="radio" name="json-link-mode" value="template"> 用樣板組出來</label><br/>
|
||||
|
||||
<div id="json-link-field-wrapper">
|
||||
連結欄位:<select id="json-link-field" class="manual-rss-input"></select><br/>
|
||||
</div>
|
||||
<div id="json-link-template-wrapper" style="display:none;">
|
||||
連結樣板:<input type="text" id="json-link-template" class="manual-rss-input" placeholder="例如 https://news.pts.org.tw/article/{id}"><br/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input type="text" id="manual-rss-title" class="manual-rss-input" placeholder="頻道顯示名稱,例如 PeoPo公民新聞"><br/>
|
||||
<button id="manual-rss-next" class="btn btn-primary">下一步:選擇分類</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="channels" style="display:none; text-align:center;">
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -42,4 +105,4 @@
|
|||
<script type="text/javascript">
|
||||
var I18n = {};
|
||||
I18n.locale = "<%= I18n.locale.to_s %>";
|
||||
</script>
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@ Rails.application.routes.draw do
|
|||
scope "(:locale)", locale: Regexp.new(locales.join("|")) do
|
||||
namespace :admin do
|
||||
get "/feeds/get_channel_list", to: 'feeds#get_channel_list'
|
||||
get "/feeds/rss_fields", to: 'feeds#rss_fields'
|
||||
get "/feeds/json_top_keys", to: 'feeds#json_top_keys'
|
||||
get "/feeds/json_item_fields", to: 'feeds#json_item_fields'
|
||||
post "/feeds/get_feed_list", to: 'feeds#get_feed_list'
|
||||
get "/feeds/get_category_list", to: 'feeds#get_category_list'
|
||||
post "/feeds/subscribe", to: 'feeds#subscribe'
|
||||
|
|
|
|||
Loading…
Reference in New Issue