-
-
Notifications
You must be signed in to change notification settings - Fork 881
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature support promised custom node render #594
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,7 +5,7 @@ | |
* Project Home: | ||
* https://github.com/hizzgdev/jsmind/ | ||
*/ | ||
import { logger, EventType } from './jsmind.common.js'; | ||
import { logger, EventType, then_if_promise, is_promise } from './jsmind.common.js'; | ||
import { $ } from './jsmind.dom.js'; | ||
import { init_graph } from './jsmind.graph.js'; | ||
import { util } from './jsmind.util.js'; | ||
|
@@ -137,10 +137,10 @@ export class ViewProvider { | |
} | ||
} | ||
load() { | ||
logger.debug('view.load'); | ||
this.setup_canvas_draggable(this.opts.draggable); | ||
this.init_nodes(); | ||
const init_res = this.init_nodes(); | ||
this._initialized = true; | ||
return init_res; | ||
} | ||
expand_size() { | ||
var min_size = this.layout.get_min_size(); | ||
|
@@ -165,21 +165,26 @@ export class ViewProvider { | |
init_nodes() { | ||
var nodes = this.jm.mind.nodes; | ||
var doc_frag = $.d.createDocumentFragment(); | ||
for (var nodeid in nodes) { | ||
this.create_node_element(nodes[nodeid], doc_frag); | ||
const promises = []; | ||
|
||
for (let nodeid in nodes) { | ||
promises.push( | ||
this.create_node_element(nodes[nodeid], doc_frag).then(() => { | ||
this.run_in_c11y_mode_if_needed(() => { | ||
this.init_nodes_size(nodes[nodeid]); | ||
}); | ||
}) | ||
); | ||
} | ||
this.e_nodes.appendChild(doc_frag); | ||
|
||
this.run_in_c11y_mode_if_needed(() => { | ||
for (var nodeid in nodes) { | ||
this.init_nodes_size(nodes[nodeid]); | ||
} | ||
}); | ||
return Promise.all(promises); //该 Promise 在所有子 Promise 完成后解决 | ||
} | ||
add_node(node) { | ||
this.create_node_element(node, this.e_nodes); | ||
this.run_in_c11y_mode_if_needed(() => { | ||
this.init_nodes_size(node); | ||
//logger.info('[view.add_node] node:', node); | ||
return this.create_node_element(node, this.e_nodes).then(() => { | ||
this.run_in_c11y_mode_if_needed(() => { | ||
this.init_nodes_size(node); | ||
}); | ||
}); | ||
} | ||
run_in_c11y_mode_if_needed(func) { | ||
|
@@ -218,15 +223,17 @@ export class ViewProvider { | |
parent_node.appendChild(d_e); | ||
view_data.expander = d_e; | ||
} | ||
let render_promise = Promise.resolve(); | ||
if (!!node.topic) { | ||
this.render_node(d, node); | ||
render_promise = this.render_node(d, node); | ||
} | ||
d.setAttribute('nodeid', node.id); | ||
d.style.visibility = 'hidden'; | ||
this._reset_node_custom_style(d, node.data); | ||
|
||
parent_node.appendChild(d); | ||
view_data.element = d; | ||
return render_promise; | ||
} | ||
remove_node(node) { | ||
if (this.selected_node != null && this.selected_node.id == node.id) { | ||
|
@@ -252,20 +259,43 @@ export class ViewProvider { | |
} | ||
update_node(node) { | ||
var view_data = node._data.view; | ||
var element = view_data.element; | ||
let element = view_data.element; | ||
let render_promise = Promise.resolve(); | ||
if (!!node.topic) { | ||
this.render_node(element, node); | ||
} | ||
if (this.layout.is_visible(node)) { | ||
view_data.width = element.clientWidth; | ||
view_data.height = element.clientHeight; | ||
} else { | ||
let origin_style = element.getAttribute('style'); | ||
element.style = 'visibility: visible; left:0; top:0;'; | ||
view_data.width = element.clientWidth; | ||
view_data.height = element.clientHeight; | ||
element.style = origin_style; | ||
//const obj = this.render_node(element, node); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 可能需要再测试一下拖动节点到其它 parent 的情况 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 哦,拖动我没用到,还没测过。回头补上 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 我在 https://github.com/hqm19/jsmind-react 中,额外引入 jsmind.draggable-node.js 后:
原来可以work的功能就报错了:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. https://github.com/hizzgdev/jsmind/blob/master/docs/zh/plugin-screenshot.md 试试这样 <script>
import domtoimage from 'dom-to-image';
import jsMind from 'jsmind'
import 'jsmind/screenshot'
import 'jsmind/style/jsmind.css'
// ...
var jm = new jsMind(options);
jm.show(mind_data);
// export current mindmap to an image
jm.shoot()
</script> There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 拖动节点会有bug, |
||
// 这里如果直接复用 element 来渲染, react 会报错: Warning: render(...): It looks like the React-rendered | ||
// content of this container was removed without using React. This is not supported and will cause errors. | ||
// Instead, call ReactDOM.unmountComponentAtNode to empty a container. | ||
// const obj = this.render_node(element, node); | ||
// 所以新建一个节点来渲染,并替换掉原来的节点 | ||
let d = element; | ||
if (view_data.promise_rendered) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 为什么只在 update_node 时才需要做这个判断? add 的时候需要吗? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 第一次渲染的时候不会有问题。同一个 容器 第二次渲染的时候才会报错。与这个问题很像: facebook/react#17547 可能与 DocumentFragment 的使用有关。所以只需在 update 时规避这个问题即可 |
||
d = $.c('jmnode'); | ||
} | ||
|
||
render_promise = this.render_node(d, node).then(() => { | ||
if (!!element.parentNode) { | ||
element.parentNode.replaceChild(d, element); | ||
} | ||
view_data.element = d; | ||
element = d; | ||
d.setAttribute('nodeid', node.id); | ||
d.style.visibility = 'hidden'; | ||
this._reset_node_custom_style(d, node.data); | ||
}); | ||
} | ||
return render_promise.then(() => { | ||
if (this.layout.is_visible(node)) { | ||
view_data.width = element.clientWidth; | ||
view_data.height = element.clientHeight; | ||
} else { | ||
let origin_style = element.getAttribute('style'); | ||
element.style = 'visibility: visible; left:0; top:0;'; | ||
view_data.width = element.clientWidth; | ||
view_data.height = element.clientHeight; | ||
element.style = origin_style; | ||
} | ||
}); | ||
} | ||
select_node(node) { | ||
if (!!this.selected_node) { | ||
|
@@ -314,6 +344,7 @@ export class ViewProvider { | |
this.e_editor.select(); | ||
} | ||
edit_node_end() { | ||
let render_promise; | ||
if (this.editing_node != null) { | ||
var node = this.editing_node; | ||
this.editing_node = null; | ||
|
@@ -322,13 +353,17 @@ export class ViewProvider { | |
var topic = this.e_editor.value; | ||
element.style.zIndex = 'auto'; | ||
element.removeChild(this.e_editor); | ||
if (util.text.is_empty(topic) || node.topic === topic) { | ||
this.render_node(element, node); | ||
} else { | ||
this.jm.update_node(node.id, topic); | ||
|
||
//logger.info('[view.edit_node_end] node:', node); | ||
let obj = this.jm.update_node(node.id, topic); | ||
if (is_promise(obj)) { | ||
render_promise = obj; | ||
} | ||
} | ||
this.e_panel.focus(); | ||
const _this = this; | ||
then_if_promise(render_promise, () => { | ||
_this.e_panel.focus(); | ||
}); | ||
} | ||
get_view_offset() { | ||
var bounds = this.layout.bounds; | ||
|
@@ -492,12 +527,18 @@ export class ViewProvider { | |
} else { | ||
$.t(ele, node.topic); | ||
} | ||
return Promise.resolve(); | ||
} | ||
_custom_node_render(ele, node) { | ||
let rendered = this.opts.custom_node_render(this.jm, ele, node); | ||
if (!rendered) { | ||
this._default_node_render(ele, node); | ||
let obj = this.opts.custom_node_render(this.jm, ele, node); | ||
if (is_promise(obj)) { | ||
node._data.view.promise_rendered = true; | ||
return obj; | ||
} | ||
if (!obj) { | ||
return this._default_node_render(ele, node); | ||
} | ||
return Promise.resolve(); | ||
} | ||
reset_node_custom_style(node) { | ||
this._reset_node_custom_style(node._data.view.element, node.data); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这里按说就会返回一个 Promise 对象了吧。那么 API 里的 add_node 这个方法的返回值也就是一个 Promise 了,我再考虑考虑,看这样搞是不是动静有点儿大,相当于不能向后兼容了。