added mind map
This commit is contained in:
parent
ed5c0a4223
commit
f55873a425
|
@ -29,14 +29,29 @@ export const INITIAL_MIND = {
|
||||||
|
|
||||||
// 模擬打 API
|
// 模擬打 API
|
||||||
// Simulate an API call to search based on the query
|
// Simulate an API call to search based on the query
|
||||||
export async function mockSearchApi(query) {
|
export async function mockSearchApi(query, tableUID) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve, reject) => {
|
||||||
setTimeout(() => {
|
const xhr = new XMLHttpRequest();
|
||||||
resolve([
|
xhr.open("GET", '/admin/universal_tables/get_entries?uid=' + tableUID + "&q=" + query + "&links=true");
|
||||||
{ text: `${query} 建議1`, link: `https://example.com/${query}1` },
|
xhr.setRequestHeader("Accept", "application/json");
|
||||||
{ text: `${query} 建議2`, link: `https://example.com/${query}2` },
|
|
||||||
{ text: `${query} 建議3`, link: `https://example.com/${query}3` },
|
xhr.onload = function () {
|
||||||
])
|
if (xhr.status >= 200 && xhr.status < 300) {
|
||||||
}, 500)
|
try {
|
||||||
})
|
const data = JSON.parse(xhr.responseText);
|
||||||
|
resolve(data); // success
|
||||||
|
} catch (e) {
|
||||||
|
reject(new Error("Invalid JSON response"));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
reject(new Error(`Request failed with status ${xhr.status}`));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
xhr.onerror = function () {
|
||||||
|
reject(new Error("Network error"));
|
||||||
|
};
|
||||||
|
|
||||||
|
xhr.send();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,8 +33,8 @@ export function initJsmind(mind, options, isEditable) {
|
||||||
// 掛載附加模組(遠程搜尋 & 工具列)
|
// 掛載附加模組(遠程搜尋 & 工具列)
|
||||||
// Attach additional modules (Remote search & Toolbar)
|
// Attach additional modules (Remote search & Toolbar)
|
||||||
if (isEditable) {
|
if (isEditable) {
|
||||||
new JsmindSearch(jm, mockSearchApi)
|
new JsmindSearch(jm, mockSearchApi, options.tableUID);
|
||||||
new JsmindToolbar(jm)
|
new JsmindToolbar(jm, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
return jm
|
return jm
|
||||||
|
|
|
@ -14,13 +14,14 @@ export class JsmindSearch {
|
||||||
* Constructor for search
|
* Constructor for search
|
||||||
* @param {Object} jm - jsMind 實例 (jsMind instance)
|
* @param {Object} jm - jsMind 實例 (jsMind instance)
|
||||||
* @param {Function} searchAPI - 遠程搜尋 API 函式 (Remote search API function)
|
* @param {Function} searchAPI - 遠程搜尋 API 函式 (Remote search API function)
|
||||||
|
* @param {string} tableUID
|
||||||
*/
|
*/
|
||||||
constructor(jm, searchAPI) {
|
constructor(jm, searchAPI, tableUID) {
|
||||||
this.jm = jm
|
this.jm = jm
|
||||||
this.searchAPI = searchAPI
|
this.searchAPI = searchAPI
|
||||||
this.container = document.getElementById(jm.options.container)
|
this.container = document.getElementById(jm.options.container)
|
||||||
this.suggestionBox = null
|
this.suggestionBox = null
|
||||||
|
this.tableUID = tableUID
|
||||||
this.init()
|
this.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,8 +78,9 @@ export class JsmindSearch {
|
||||||
async onInput(node, e) {
|
async onInput(node, e) {
|
||||||
const query = e.target.value.trim()
|
const query = e.target.value.trim()
|
||||||
if (!query) return
|
if (!query) return
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 500));
|
||||||
try {
|
try {
|
||||||
const results = await this.searchAPI(query)
|
const results = await this.searchAPI(query, this.tableUID)
|
||||||
this.showSuggestion(node, e.target, results)
|
this.showSuggestion(node, e.target, results)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Search API error handling
|
// Search API error handling
|
||||||
|
|
|
@ -13,8 +13,9 @@ export class JsmindToolbar {
|
||||||
* 建構工具列
|
* 建構工具列
|
||||||
* Constructor for toolbar
|
* Constructor for toolbar
|
||||||
* @param {Object} jm - jsMind 實例 (jsMind instance)
|
* @param {Object} jm - jsMind 實例 (jsMind instance)
|
||||||
|
* @param {Object} options - jsMind 實例 (options)
|
||||||
*/
|
*/
|
||||||
constructor(jm) {
|
constructor(jm, options) {
|
||||||
this.jm = jm
|
this.jm = jm
|
||||||
this.container = document.getElementById(jm.options.container)
|
this.container = document.getElementById(jm.options.container)
|
||||||
this.toolbarNodeId = null
|
this.toolbarNodeId = null
|
||||||
|
@ -22,7 +23,7 @@ export class JsmindToolbar {
|
||||||
this.bgColorPalette = null
|
this.bgColorPalette = null
|
||||||
this.strokeColorPalette = null
|
this.strokeColorPalette = null
|
||||||
this.textColorPalette = null
|
this.textColorPalette = null
|
||||||
|
this.options = options
|
||||||
this.init()
|
this.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,21 +79,21 @@ export class JsmindToolbar {
|
||||||
// 建立工具列按鈕
|
// 建立工具列按鈕
|
||||||
// Create toolbar buttons
|
// Create toolbar buttons
|
||||||
const buttons = [
|
const buttons = [
|
||||||
{ id: 'toolbar-add-child-btn', text: '新增', onClick: this.handleAddChild.bind(this) },
|
{ id: 'toolbar-add-child-btn', text: this.options.text.addNode, onClick: this.handleAddChild.bind(this) },
|
||||||
{ id: 'toolbar-delete-btn', text: '刪除', onClick: this.handleDelete.bind(this) },
|
{ id: 'toolbar-delete-btn', text: this.options.text.deleteNode, onClick: this.handleDelete.bind(this) },
|
||||||
{
|
{
|
||||||
id: 'toolbar-stroke-color-btn',
|
id: 'toolbar-stroke-color-btn',
|
||||||
text: '線條顏色',
|
text: this.options.text.strokeColor,
|
||||||
onClick: this.handleStrokeColor.bind(this),
|
onClick: this.handleStrokeColor.bind(this),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'toolbar-bg-color-btn',
|
id: 'toolbar-bg-color-btn',
|
||||||
text: '背景顏色',
|
text: this.options.text.bgColor,
|
||||||
onClick: this.handleBgColor.bind(this),
|
onClick: this.handleBgColor.bind(this),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'toolbar-text-color-btn',
|
id: 'toolbar-text-color-btn',
|
||||||
text: '文字顏色',
|
text: this.options.text.textColor,
|
||||||
onClick: this.handleTextColor.bind(this),
|
onClick: this.handleTextColor.bind(this),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
|
@ -9,4 +9,20 @@ class Admin::MindMapsController < OrbitAdminController
|
||||||
@mind_map = table.mind_map
|
@mind_map = table.mind_map
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
mind_map = MindMap.find(params[:id])
|
||||||
|
mind_params = mind_map_params
|
||||||
|
mind_params[:mind_map_data] = JSON.parse(mind_params[:mind_map_data])
|
||||||
|
mind_map.update_attributes(mind_map_params)
|
||||||
|
mind_map.save
|
||||||
|
redirect_to admin_universal_tables_path
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def mind_map_params
|
||||||
|
params.require(:mind_map).permit!
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -53,11 +53,20 @@ class Admin::UniversalTablesController < OrbitAdminController
|
||||||
data = []
|
data = []
|
||||||
if !table.nil?
|
if !table.nil?
|
||||||
enteries = search_data(table, 50)
|
enteries = search_data(table, 50)
|
||||||
|
ma = ModuleApp.find_by_key("universal_table")
|
||||||
enteries.each do |entry|
|
enteries.each do |entry|
|
||||||
data << {
|
if params["links"].present?
|
||||||
"id" => entry.id.to_s,
|
data << {
|
||||||
"text" => entry.column_entries.first.text
|
"id" => entry.id.to_s,
|
||||||
}
|
"text" => entry.column_entries.first.text,
|
||||||
|
"link" => OrbitHelper.cal_url_to_show(ma,entry)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
data << {
|
||||||
|
"id" => entry.id.to_s,
|
||||||
|
"text" => entry.column_entries.first.text
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
render :json => data.to_json
|
render :json => data.to_json
|
||||||
|
|
|
@ -351,4 +351,8 @@ class UniversalTablesController < ApplicationController
|
||||||
render :file => "#{Rails.root}/app/views/errors/404.html", :layout => false, :status => :not_found
|
render :file => "#{Rails.root}/app/views/errors/404.html", :layout => false, :status => :not_found
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def mind_map
|
||||||
|
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,7 +4,8 @@ class MindMap
|
||||||
include Slug
|
include Slug
|
||||||
|
|
||||||
field :title, as: :slug_title, localize: true
|
field :title, as: :slug_title, localize: true
|
||||||
|
field :mind_map_data, type: Array, default: []
|
||||||
|
|
||||||
belongs_to :u_table
|
belongs_to :u_table
|
||||||
has_many :mind_map_nodes, :dependent => :destroy
|
# has_many :mind_map_nodes, :dependent => :destroy
|
||||||
end
|
end
|
||||||
|
|
|
@ -31,9 +31,15 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="control-group">
|
<div class="control-group">
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<button id="toggle_editable">Disable Editing</button>
|
<button id="toggle_editable"><%= t("universal_table.disable_editing") %></button>
|
||||||
<button id="save_mind_map">Save Mind Map</button>
|
<button id="save_mind_map"><%= t("universal_table.save_mind_map") %></button>
|
||||||
</div>
|
</div>
|
||||||
<div id="jsmind_container"></div>
|
<div id="jsmind_container"></div>
|
||||||
</div>
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
<fieldset class="utable-content">
|
||||||
|
<div class="form-actions">
|
||||||
|
<%= f.hidden_field :mind_map_data, id: "mind_map_data_field", value: "" %>
|
||||||
|
<input class="btn btn-primary pull-right" name="commit" id="save_mind_map" type="submit" value="<%= t("save") %>">
|
||||||
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
|
@ -2,7 +2,7 @@
|
||||||
<%= stylesheet_link_tag "universal_table/universal-table" %>
|
<%= stylesheet_link_tag "universal_table/universal-table" %>
|
||||||
<%= stylesheet_link_tag "mind_map/mindmap" %>
|
<%= stylesheet_link_tag "mind_map/mindmap" %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<%= form_for @mind_map, url: admin_mind_map_path(@mind_map), html: {class: "form-horizontal main-forms"} do |f| %>
|
<%= form_for @mind_map, url: admin_mind_map_path(@mind_map.id), html: {class: "form-horizontal main-forms", id: "mind_map_form"} do |f| %>
|
||||||
<%= render :partial => "form", locals: {f: f} %>
|
<%= render :partial => "form", locals: {f: f} %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<script type="module">
|
<script type="module">
|
||||||
|
@ -21,7 +21,15 @@
|
||||||
|
|
||||||
// 心智圖初始數據
|
// 心智圖初始數據
|
||||||
// Initial mind map data
|
// Initial mind map data
|
||||||
|
<% if @mind_map.mind_map_data.empty? %>
|
||||||
let mind = INITIAL_MIND
|
let mind = INITIAL_MIND
|
||||||
|
<% else %>
|
||||||
|
let mind = {
|
||||||
|
meta: {},
|
||||||
|
format: 'node_array',
|
||||||
|
data: <%= raw @mind_map.mind_map_data.to_json %>
|
||||||
|
}
|
||||||
|
<% end %>
|
||||||
|
|
||||||
// 心智圖自訂選項(可參考 jsmind 官方文檔)
|
// 心智圖自訂選項(可參考 jsmind 官方文檔)
|
||||||
// Custom options for the mind map (refer to the jsmind official documentation)
|
// Custom options for the mind map (refer to the jsmind official documentation)
|
||||||
|
@ -30,6 +38,14 @@
|
||||||
editable: isEditable,
|
editable: isEditable,
|
||||||
theme: 'primary',
|
theme: 'primary',
|
||||||
mode: 'full',
|
mode: 'full',
|
||||||
|
tableUID: '<%= @mind_map.u_table.uid %>',
|
||||||
|
text: {
|
||||||
|
addNode: "<%= t("universal_table.add_node") %>",
|
||||||
|
deleteNode: "<%= t("universal_table.delete_node") %>",
|
||||||
|
strokeColor: "<%= t("universal_table.stroke_color") %>",
|
||||||
|
bgColor: "<%= t("universal_table.bg_color") %>",
|
||||||
|
textColor: "<%= t("universal_table.text_color") %>"
|
||||||
|
},
|
||||||
view: {
|
view: {
|
||||||
engine: 'svg',
|
engine: 'svg',
|
||||||
draggable: true,
|
draggable: true,
|
||||||
|
@ -53,8 +69,8 @@
|
||||||
document.getElementById('save_mind_map').addEventListener('click', (e) => {
|
document.getElementById('save_mind_map').addEventListener('click', (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
let data = getJsmindData(jm)
|
let data = getJsmindData(jm);
|
||||||
console.log(data)
|
console.log(data);
|
||||||
})
|
})
|
||||||
|
|
||||||
// 調整可編輯狀態
|
// 調整可編輯狀態
|
||||||
|
@ -62,11 +78,19 @@
|
||||||
document.getElementById('toggle_editable').addEventListener('click', (e) => {
|
document.getElementById('toggle_editable').addEventListener('click', (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
isEditable = !isEditable
|
isEditable = !isEditable;
|
||||||
e.target.innerHTML = isEditable ? 'Disable Editing' : 'Enable Editing'
|
e.target.innerHTML = isEditable ? '<%= t("universal_table.disable_editing") %>' : '<%= t("universal_table.enable_editing") %>';
|
||||||
|
|
||||||
mind = getJsmindData(jm)
|
mind = getJsmindData(jm);
|
||||||
jm = initJsmind(mind, options, isEditable)
|
jm = initJsmind(mind, options, isEditable);
|
||||||
return false;
|
return false;
|
||||||
})
|
})
|
||||||
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
const form = document.getElementById("mind_map_form");
|
||||||
|
const hiddenField = document.getElementById("mind_map_data_field");
|
||||||
|
form.addEventListener("submit", function (e) {
|
||||||
|
const mindMapData = getJsmindData(jm);
|
||||||
|
hiddenField.value = JSON.stringify(mindMapData.data);
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -21,4 +21,12 @@ en:
|
||||||
drag_file_to_here: Drag file to here
|
drag_file_to_here: Drag file to here
|
||||||
show_lang: Language
|
show_lang: Language
|
||||||
downloaded_times: Downloaded Times
|
downloaded_times: Downloaded Times
|
||||||
mind_map: Mind Map
|
mind_map: Mind Map
|
||||||
|
add_node: Add Node
|
||||||
|
delete_node: Delete Node
|
||||||
|
stroke_color: Line Color
|
||||||
|
bg_color: Background Color
|
||||||
|
text_color: Text Color
|
||||||
|
disable_editing: Disable editing
|
||||||
|
enable_editing: Enable editing
|
||||||
|
save_mind_map: Save mind map
|
|
@ -21,4 +21,12 @@ zh_tw:
|
||||||
drag_file_to_here: 拖移檔案到此
|
drag_file_to_here: 拖移檔案到此
|
||||||
show_lang: 呈現語系
|
show_lang: 呈現語系
|
||||||
downloaded_times: 下載次數
|
downloaded_times: 下載次數
|
||||||
mind_map: Mind Map
|
mind_map: Mind Map
|
||||||
|
add_node: 新增
|
||||||
|
delete_node: 刪除
|
||||||
|
stroke_color: 線條顏色
|
||||||
|
bg_color: 背景顏色
|
||||||
|
text_color: 文字顏色
|
||||||
|
disable_editing: Disable editing
|
||||||
|
enable_editing: Enable editing
|
||||||
|
save_mind_map: Save mind map
|
Loading…
Reference in New Issue