Commit c921bb14 authored by Ronny's avatar Ronny Committed by techird

1. protocal添加mindmanager xmind freemind解析

2. 添加lib zip、inflate、xml2json,同时修改import.php和index.html
3. social.js添加格式解析
4. dropfile.js添加格式解析
5. minder.data.js将import改成支持同步和异步导入
6. saveto.js 如果没有encode则不添加到dropmenu栏
parent 9c259ca5
......@@ -65,6 +65,9 @@ $dependency = Array(
,'src/adapter/node.js'
,'src/adapter/contextmenu.js'
,'src/adapter/dialog.js'
,'src/protocal/xmind.js'
,'src/protocal/freemind.js'
,'src/protocal/mindmanager.js'
,'src/protocal/plain.js'
,'src/protocal/json.js'
,'src/protocal/png.js'
......
......@@ -14,6 +14,8 @@
<script src="../kityminder.config.js" charset="utf-8"></script>
<script src="../lang/zh-cn/zh-cn.js" charset="utf-8"></script>
<script src="../lib/zip.js" charset="utf-8"></script>
<script src="../lib/jquery.xml2json.js" charset="utf-8"></script>
<script src="../lib/baidu-frontia-js-full-1.0.0.js" charset="utf-8"></script>
<script src="../social/draftmanager.js" charset="utf-8"></script>
<script src="../social/social.js" charset="utf-8"></script>
......@@ -45,6 +47,6 @@
</body>
<script>
// create km instance
window.km = KM.getKityMinder('kityminder');
window.km = KM.getKityMinder('kityminder');
</script>
</html>
\ No newline at end of file
This diff is collapsed.
/*
### jQuery XML to JSON Plugin v1.3 - 2013-02-18 ###
* http://www.fyneworks.com/ - diego@fyneworks.com
* Licensed under http://en.wikipedia.org/wiki/MIT_License
###
Website: http://www.fyneworks.com/jquery/xml-to-json/
*//*
# INSPIRED BY: http://www.terracoder.com/
AND: http://www.thomasfrank.se/xml_to_json.html
AND: http://www.kawa.net/works/js/xml/objtree-e.html
*//*
This simple script converts XML (document of code) into a JSON object. It is the combination of 2
'xml to json' great parsers (see below) which allows for both 'simple' and 'extended' parsing modes.
*/
// Avoid collisions
;if(window.jQuery) (function($){
// Add function to jQuery namespace
$.extend({
// converts xml documents and xml text to json object
xml2json: function(xml, extended) {
if(!xml) return {}; // quick fail
//### PARSER LIBRARY
// Core function
function parseXML(node, simple){
if(!node) return null;
var txt = '', obj = null, att = null;
var nt = node.nodeType, nn = jsVar(node.localName || node.nodeName);
var nv = node.text || node.nodeValue || '';
/*DBG*/ //if(window.console) console.log(['x2j',nn,nt,nv.length+' bytes']);
if(node.childNodes){
if(node.childNodes.length>0){
/*DBG*/ //if(window.console) console.log(['x2j',nn,'CHILDREN',node.childNodes]);
$.each(node.childNodes, function(n,cn){
var cnt = cn.nodeType, cnn = jsVar(cn.localName || cn.nodeName);
var cnv = cn.text || cn.nodeValue || '';
/*DBG*/ //if(window.console) console.log(['x2j',nn,'node>a',cnn,cnt,cnv]);
if(cnt == 8){
/*DBG*/ //if(window.console) console.log(['x2j',nn,'node>b',cnn,'COMMENT (ignore)']);
return; // ignore comment node
}
else if(cnt == 3 || cnt == 4 || !cnn){
// ignore white-space in between tags
if(cnv.match(/^\s+$/)){
/*DBG*/ //if(window.console) console.log(['x2j',nn,'node>c',cnn,'WHITE-SPACE (ignore)']);
return;
};
/*DBG*/ //if(window.console) console.log(['x2j',nn,'node>d',cnn,'TEXT']);
txt += cnv.replace(/^\s+/,'').replace(/\s+$/,'');
// make sure we ditch trailing spaces from markup
}
else{
/*DBG*/ //if(window.console) console.log(['x2j',nn,'node>e',cnn,'OBJECT']);
obj = obj || {};
if(obj[cnn]){
/*DBG*/ //if(window.console) console.log(['x2j',nn,'node>f',cnn,'ARRAY']);
// http://forum.jquery.com/topic/jquery-jquery-xml2json-problems-when-siblings-of-the-same-tagname-only-have-a-textnode-as-a-child
if(!obj[cnn].length) obj[cnn] = myArr(obj[cnn]);
obj[cnn] = myArr(obj[cnn]);
obj[cnn][ obj[cnn].length ] = parseXML(cn, true/* simple */);
obj[cnn].length = obj[cnn].length;
}
else{
/*DBG*/ //if(window.console) console.log(['x2j',nn,'node>g',cnn,'dig deeper...']);
obj[cnn] = parseXML(cn);
};
};
});
};//node.childNodes.length>0
};//node.childNodes
if(node.attributes){
if(node.attributes.length>0){
/*DBG*/ //if(window.console) console.log(['x2j',nn,'ATTRIBUTES',node.attributes])
att = {}; obj = obj || {};
$.each(node.attributes, function(a,at){
var atn = jsVar(at.name), atv = at.value;
att[atn] = atv;
if(obj[atn]){
/*DBG*/ //if(window.console) console.log(['x2j',nn,'attr>',atn,'ARRAY']);
// http://forum.jquery.com/topic/jquery-jquery-xml2json-problems-when-siblings-of-the-same-tagname-only-have-a-textnode-as-a-child
//if(!obj[atn].length) obj[atn] = myArr(obj[atn]);//[ obj[ atn ] ];
obj[cnn] = myArr(obj[cnn]);
obj[atn][ obj[atn].length ] = atv;
obj[atn].length = obj[atn].length;
}
else{
/*DBG*/ //if(window.console) console.log(['x2j',nn,'attr>',atn,'TEXT']);
obj[atn] = atv;
};
});
//obj['attributes'] = att;
};//node.attributes.length>0
};//node.attributes
if(obj){
obj = $.extend( (txt!='' ? new String(txt) : {}),/* {text:txt},*/ obj || {}/*, att || {}*/);
//txt = (obj.text) ? (typeof(obj.text)=='object' ? obj.text : [obj.text || '']).concat([txt]) : txt;
txt = (obj.text) ? ([obj.text || '']).concat([txt]) : txt;
if(txt) obj.text = txt;
txt = '';
};
var out = obj || txt;
//console.log([extended, simple, out]);
if(extended){
if(txt) out = {};//new String(out);
txt = out.text || txt || '';
if(txt) out.text = txt;
if(!simple) out = myArr(out);
};
return out;
};// parseXML
// Core Function End
// Utility functions
var jsVar = function(s){ return String(s || '').replace(/-/g,"_"); };
// NEW isNum function: 01/09/2010
// Thanks to Emile Grau, GigaTecnologies S.L., www.gigatransfer.com, www.mygigamail.com
function isNum(s){
// based on utility function isNum from xml2json plugin (http://www.fyneworks.com/ - diego@fyneworks.com)
// few bugs corrected from original function :
// - syntax error : regexp.test(string) instead of string.test(reg)
// - regexp modified to accept comma as decimal mark (latin syntax : 25,24 )
// - regexp modified to reject if no number before decimal mark : ".7" is not accepted
// - string is "trimmed", allowing to accept space at the beginning and end of string
var regexp=/^((-)?([0-9]+)(([\.\,]{0,1})([0-9]+))?$)/
return (typeof s == "number") || regexp.test(String((s && typeof s == "string") ? jQuery.trim(s) : ''));
};
// OLD isNum function: (for reference only)
//var isNum = function(s){ return (typeof s == "number") || String((s && typeof s == "string") ? s : '').test(/^((-)?([0-9]*)((\.{0,1})([0-9]+))?$)/); };
var myArr = function(o){
// http://forum.jquery.com/topic/jquery-jquery-xml2json-problems-when-siblings-of-the-same-tagname-only-have-a-textnode-as-a-child
//if(!o.length) o = [ o ]; o.length=o.length;
if(!$.isArray(o)) o = [ o ]; o.length=o.length;
// here is where you can attach additional functionality, such as searching and sorting...
return o;
};
// Utility functions End
//### PARSER LIBRARY END
// Convert plain text to xml
if(typeof xml=='string') xml = $.text2xml(xml);
// Quick fail if not xml (or if this is a node)
if(!xml.nodeType) return;
if(xml.nodeType == 3 || xml.nodeType == 4) return xml.nodeValue;
// Find xml root node
var root = (xml.nodeType == 9) ? xml.documentElement : xml;
// Convert xml to json
var out = parseXML(root, true /* simple */);
// Clean-up memory
xml = null; root = null;
// Send output
return out;
},
// Convert text to XML DOM
text2xml: function(str) {
// NOTE: I'd like to use jQuery for this, but jQuery makes all tags uppercase
//return $(xml)[0];
/* prior to jquery 1.9 */
/*
var out;
try{
var xml = ((!$.support.opacity && !$.support.style))?new ActiveXObject("Microsoft.XMLDOM"):new DOMParser();
xml.async = false;
}catch(e){ throw new Error("XML Parser could not be instantiated") };
try{
if((!$.support.opacity && !$.support.style)) out = (xml.loadXML(str))?xml:false;
else out = xml.parseFromString(str, "text/xml");
}catch(e){ throw new Error("Error parsing XML string") };
return out;
*/
/* jquery 1.9+ */
return $.parseXML(str);
}
}); // extend $
})(jQuery);
\ No newline at end of file
This diff is collapsed.
......@@ -74,9 +74,8 @@ $( function () {
// 脑图实例
minder = window.km,
// 草稿箱
draftManager = new window.DraftManager( minder ),
draftManager = window.draftManager || new window.DraftManager( minder ),
// 当前是否要检测文档内容是否变化的开关
watchingChanges = true,
......@@ -316,32 +315,93 @@ $( function () {
sto.getFileUrl( remotePath, {
success: function ( url ) {
$.ajax( {
cache: false,
url: url,
dataType: 'text',
success: function ( result ) {
watchingChanges = false;
// the url to download the file on cloud dist
var arr = remotePath.split( '.' );
var format = arr[ arr.length - 1 ];
if ( format in loadFile ) {
loadFile[ format ]( url );
}
},
error: notice
} );
}
var loadFile = {
'km': loadPlainType,
'json': loadPlainType,
'xmind': loadXMind,
'mmap': loadMindManager,
'mm': loadFreeMind
};
function loadPlainType( url ) {
$.ajax( {
cache: false,
url: url,
dataType: 'text',
success: function ( result ) {
importFile( result, 'json' );
}
} );
}
minder.importData( result, 'json' );
function loadXMind( url ) {
if ( !draftManager.openByPath( remotePath ) ) {
draftManager.create();
}
draftManager.save( remotePath );
draftManager.sync();
var xhr = new XMLHttpRequest();
xhr.open( "get", url, true );
xhr.responseType = "blob";
xhr.onload = function () {
if ( this.status == 200 && this.readyState ) {
var blob = this.response;
importFile( blob, 'xmind' );
}
};
xhr.send();
}
minder.execCommand( 'camera', minder.getRoot() );
$user_btn.loading( false ).text( getFileName( remotePath ) );
function loadMindManager( url ) {
watchingChanges = true;
}
} );
},
error: notice
var xhr = new XMLHttpRequest();
xhr.open( "get", url, true );
xhr.responseType = "blob";
xhr.onload = function () {
if ( this.status == 200 && this.readyState ) {
var blob = this.response;
importFile( blob, 'mindmanager' );
}
};
xhr.send();
}
function loadFreeMind( url ) {
$.ajax( {
cache: false,
url: url,
dataType: 'text',
success: function ( result ) {
importFile( result, 'freemind' );
}
} );
}
// 见文件数据导入minder
function importFile( data, format ) {
watchingChanges = false;
minder.importData( data, format );
if ( !draftManager.openByPath( remotePath ) ) {
draftManager.create();
}
draftManager.save( remotePath );
draftManager.sync();
minder.execCommand( 'camera', minder.getRoot() );
$user_btn.loading( false ).text( getFileName( remotePath ) );
watchingChanges = true;
}
// 添加文件到最近文件列表
function addToRecentMenu( list ) {
list.splice( 12 );
......
......@@ -17,10 +17,12 @@ KM.registerToolbarUI( 'saveto', function ( name ) {
utils.each( KityMinder.getAllRegisteredProtocals(), function ( k ) {
var p = KityMinder.findProtocal( k );
var text = p.fileDescription + '(' + p.fileExtension + ')';
options.value.push( k );
options.items.push( text );
options.autowidthitem.push( $.wordCountAdaptive( text ), true );
if( p.encode ){
var text = p.fileDescription + '(' + p.fileExtension + ')';
options.value.push( k );
options.items.push( text );
options.autowidthitem.push( $.wordCountAdaptive( text ), true );
}
} );
......
......@@ -97,6 +97,18 @@ kity.extendClass( Minder, {
json = params.json || ( params.json = protocal.decode( local ) );
if ( typeof json === 'object' && 'then' in json ) {
var self = this;
json.then( local, function ( data ) {
self._afterImportData( data, params );
} );
} else {
this._afterImportData( json, params );
}
return this;
},
_afterImportData: function ( json, params ) {
this._fire( new MinderEvent( 'preimport', params, false ) );
// 删除当前所有节点
......@@ -115,7 +127,6 @@ kity.extendClass( Minder, {
this._firePharse( {
type: 'interactchange'
} );
return this;
}
} );
\ No newline at end of file
......@@ -16,15 +16,52 @@ KityMinder.registerModule( "DropFile", function () {
e.preventDefault();
e.stopPropagation();
var minder = this;
if ( e.dataTransfer.files ) {
var reader = new FileReader();
reader.onload = function ( e ) {
minder.importData( e.target.result );
};
reader.readAsText( e.dataTransfer.files[ 0 ] );
var files = e.dataTransfer.files;
if ( files ) {
var file = files[0];
var ext = file.type || (/(.)\w+$/).exec(file.name)[0];
if( (/xmind/g).test(ext) ){ //xmind zip
importSync( minder, file, 'xmind' );
}else if( (/mmap/g).test(ext) ){ // mindmanager zip
importSync( minder, file, 'mindmanager' );
}else if( (/mm/g).test(ext) ){ //freemind xml
importAsync( minder, file, 'freemind' );
}else{// txt json
importAsync( minder, file );
}
}
}
// 同步加载文件
function importSync( minder, file, protocal ){
minder.importData( file, protocal );//zip文件的import是同步的
manageDraft( minder );
minder.execCommand( 'camera', minder.getRoot() );
}
// 异步加载文件
function importAsync( minder, file, protocal ){
var reader = new FileReader();
reader.onload = function ( e ) {
minder.importData( e.target.result, protocal );//纯文本文件的import是同步的
manageDraft( minder );
minder.execCommand( 'camera', minder.getRoot() );
};
reader.readAsText( file );
}
function manageDraft( minder ){
if( !window.draftManager ){
window.draftManager = new window.DraftManager( minder );
}
window.draftManager.create();
}
return {
events: {
ready: init
......
/*
http://www.xmind.net/developer/
Parsing XMind file
XMind files are generated in XMind Workbook (.xmind) format, an open format that is based on the principles of OpenDocument. It consists of a ZIP compressed archive containing separate XML documents for content and styles, a .jpg image file for thumbnails, and directories for related attachments.
*/
KityMinder.registerProtocal( 'freemind', function () {
var markerMap = {
'full-1' : ['PriorityIcon', 1]
,'full-2' : ['PriorityIcon', 2]
,'full-3' : ['PriorityIcon', 3]
,'full-4' : ['PriorityIcon', 4]
,'full-5' : ['PriorityIcon', 5]
,'full-6' : null
,'full-7' : null
,'full-8' : null
,'full-9' : null
,'full-0' : null
};
function processTopic(topic, obj){
//处理文本
obj.data = { text : topic.TEXT };
// 处理标签
if(topic.icon){
var icons = topic.icon;
if(icons.length && icons.length > 0){
for (var i in icons) {
var type = markerMap[ icons[i]['BUILTIN'] ];
type && (obj.data[ type[0] ] = type[1]);
}
}else{
var type = markerMap[ icons['BUILTIN'] ];
type && (obj.data[ type[0] ] = type[1]);
}
}
//处理子节点
if( topic.node ){
var tmp = topic.node;
if( tmp.length && tmp.length > 0 ){ //多个子节点
obj.children = [];
for(var i in tmp){
obj.children.push({});
processTopic(tmp[i], obj.children[i]);
}
}else{ //一个子节点
obj.children = [{}];
processTopic(tmp, obj.children[0]);
}
}
};
function xml2km(xml){
var json = $.xml2json(xml);
var result = {};
processTopic(json.node, result);
return result;
};
return {
fileDescription: 'xmind格式文件',
fileExtension: '.xmind',
decode: function ( local ) {
var json = xml2km( local );
return json;
},
// recognize: recognize,
recognizePriority: -1
};
} );
/*
http://www.xmind.net/developer/
Parsing XMind file
XMind files are generated in XMind Workbook (.xmind) format, an open format that is based on the principles of OpenDocument. It consists of a ZIP compressed archive containing separate XML documents for content and styles, a .jpg image file for thumbnails, and directories for related attachments.
*/
KityMinder.registerProtocal( 'mindmanager', function () {
var markerMap = {
'urn:mindjet:Prio1' : ['PriorityIcon', 1]
,'urn:mindjet:Prio2' : ['PriorityIcon', 2]
,'urn:mindjet:Prio3' : ['PriorityIcon', 3]
,'urn:mindjet:Prio4' : ['PriorityIcon', 4]
,'urn:mindjet:Prio5' : ['PriorityIcon', 5]
,'0' : ['ProgressIcon', 1]
,'25' : ['ProgressIcon', 2]
,'50' : ['ProgressIcon', 3]
,'75' : ['ProgressIcon', 4]
,'100' : ['ProgressIcon', 5]
};
function processTopic(topic, obj){
//处理文本
obj.data = { text : topic.Text && topic.Text.PlainText || '_' }; // 节点默认的文本,没有Text属性
// 处理标签
if(topic.Task){
var type;
if(topic.Task.TaskPriority){
type = markerMap[ topic.Task.TaskPriority ];
type && (obj.data[ type[0] ] = type[1]);
}
if(topic.Task.TaskPercentage){
type = markerMap[ topic.Task.TaskPercentage ];
type && (obj.data[ type[0] ] = type[1]);
}
}
//处理子节点
if( topic.SubTopics && topic.SubTopics.Topic ){
var tmp = topic.SubTopics.Topic;
if( tmp.length && tmp.length > 0 ){ //多个子节点
obj.children = [];
for(var i in tmp){
obj.children.push({});
processTopic(tmp[i], obj.children[i]);
}
}else{ //一个子节点
obj.children = [{}];
processTopic(tmp, obj.children[0]);
}
}
};
function xml2km(xml){
var json = $.xml2json(xml);
var result = {};
processTopic(json.OneTopic.Topic, result);
return result;
};
function getEntries(file, onend) {
zip.createReader(new zip.BlobReader(file), function(zipReader) {
zipReader.getEntries(onend);
}, onerror);
};
return {
fileDescription: 'mindmanager格式文件',
fileExtension: '.mmap',
decode: function ( local ) {
return {
then : function(local, callback){
getEntries( local, function( entries ) {
entries.forEach(function( entry ) {
if(entry.filename == 'Document.xml'){
entry.getData(new zip.TextWriter(), function(text) {
var km = xml2km($.parseXML(text));
callback && callback( km );
});
}
});
});
}
};
},
// recognize: recognize,
recognizePriority: -1
};
} );
......@@ -7,7 +7,104 @@
XMind files are generated in XMind Workbook (.xmind) format, an open format that is based on the principles of OpenDocument. It consists of a ZIP compressed archive containing separate XML documents for content and styles, a .jpg image file for thumbnails, and directories for related attachments.
*/
KityMinder.registerProtocal( 'xmind', {
fileExtension: '.xmind',
KityMinder.registerProtocal( 'xmind', function () {
var markerMap = {
'priority-1' : ['PriorityIcon', 1]
,'priority-2' : ['PriorityIcon', 2]
,'priority-3' : ['PriorityIcon', 3]
,'priority-4' : ['PriorityIcon', 4]
,'priority-5' : ['PriorityIcon', 5]
,'task-start' : ['ProgressIcon', 1]
,'task-quarter' : ['ProgressIcon', 2]
,'task-half' : ['ProgressIcon', 3]
,'task-3quar' : ['ProgressIcon', 4]
,'task-done' : ['ProgressIcon', 5]
,'task-oct' : null
,'task-3oct' : null
,'task-5oct' : null
,'task-7oct' : null
};
function processTopic(topic, obj){
//处理文本
obj.data = { text : topic.title };
// 处理标签
if(topic.marker_refs && topic.marker_refs.marker_ref){
var markers = topic.marker_refs.marker_ref;
if( markers.length && markers.length > 0 ){
for (var i in markers) {
var type = markerMap[ markers[i]['marker_id'] ];
type && (obj.data[ type[0] ] = type[1]);
}
}else{
var type = markerMap[ markers['marker_id'] ];
type && (obj.data[ type[0] ] = type[1]);
}
}
//处理子节点
if( topic.children && topic.children.topics && topic.children.topics.topic ){
var tmp = topic.children.topics.topic;
if( tmp.length && tmp.length > 0 ){ //多个子节点
obj.children = [];
for(var i in tmp){
obj.children.push({});
processTopic(tmp[i], obj.children[i]);
}
}else{ //一个子节点
obj.children = [{}];
processTopic(tmp, obj.children[0]);
}
}
};
function xml2km(xml){
var json = $.xml2json(xml);
var result = {};
processTopic(json.sheet.topic, result);
return result;
};
function getEntries(file, onend) {
zip.createReader(new zip.BlobReader(file), function(zipReader) {
zipReader.getEntries(onend);
}, onerror);
};
return {
fileDescription: 'xmind格式文件',
fileExtension: '.xmind',
decode: function ( local ) {
return {
then : function(local, callback){
getEntries( local, function( entries ) {
entries.forEach(function( entry ) {
if(entry.filename == 'content.xml'){
entry.getData(new zip.TextWriter(), function(text) {
var km = xml2km($.parseXML(text));
callback && callback( km );
});
}
});
});
}
};
},
// recognize: recognize,
recognizePriority: -1
};
} );
} );
\ No newline at end of file
......@@ -10,4 +10,7 @@
## 解析和生成目标
只解析 KityMinder 支持部分的文件内容;只生成 KityMinder 和 XMind 都支持的文件内容
\ No newline at end of file
只解析 KityMinder 支持部分的文件内容;只生成 KityMinder 和 XMind 都支持的文件内容
使用zip.js解开xmind文件,根目录下的content.xml,描述脑图的结构,其中节点属性只有title对kityminder有用,以及children下面的topic(即节点)
将content.xml的结构和属性解析为xmind的km格式即可渲染
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