PopMenu.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. var Popmenu = MWF.xApplication.MinderEditor.PopMenu = new Class({
  2. Extends: MWF.widget.Common,
  3. Implements: [Options, Events],
  4. options: {
  5. "style": "default"
  6. },
  7. initialize: function (container, editor, minder, app) {
  8. this.container = container;
  9. this.app = app;
  10. this.lp = MWF.xApplication.MinderEditor.LP;
  11. this.actions = this.app.restActions;
  12. this.editor = editor;
  13. this.minder = minder;
  14. this.receiver = editor.receiver;
  15. var fsm = this.fsm = editor.fsm;
  16. this.path = "../x_component_MinderEditor/$PopMenu/";
  17. this.cssPath = this.path + this.options.style + "/css.wcss";
  18. this._loadCss();
  19. this.nodeMenu = new MWF.xApplication.MinderEditor.NodePopMenu(this.container, null, this.app, null, {
  20. nodeStyles : this.css.tooltipNode,
  21. onPostLoad : function(){
  22. this.nodeMenu.isActive = true;
  23. }.bind(this),
  24. onHide : function(){
  25. this.nodeMenu.isActive = false;
  26. }.bind(this)
  27. }, {});
  28. this.nodeMenu.popmenu = this;
  29. this.nodeMenu.minder = this.minder;
  30. fsm.when('normal -> popmenu', function(exit, enter, reason) {
  31. var node = this.minder.getSelectedNode();
  32. var position;
  33. if (node) {
  34. var box = node.getRenderBox();
  35. position = {
  36. x: box.cx,
  37. y: box.cy
  38. };
  39. this.active('main', position)
  40. }
  41. }.bind(this));
  42. fsm.when('popmenu -> popmenu', function(exit, enter, reason) {
  43. var node = this.minder.getSelectedNode();
  44. var position;
  45. if (node) {
  46. var box = node.getRenderBox();
  47. position = {
  48. x: box.cx,
  49. y: box.cy
  50. };
  51. this.active('main', position)
  52. }
  53. }.bind(this));
  54. fsm.when('popmenu -> normal', function(exit, enter, reason, e) {
  55. //if (reason == 'shortcut-handle') {
  56. //var handleResult = this.dispatch(e);
  57. //if (handleResult) {
  58. // e.preventDefault();
  59. //} else {
  60. // this.minder.dispatchKeyEvent(e);
  61. //}
  62. //}else
  63. if( reason == "popmenu-idle" ){
  64. if( this.nodeMenu.isActive ){
  65. this.nodeMenu.hide();
  66. }
  67. }
  68. }.bind(this));
  69. //fsm.when('popmenu -> input', function(exit, enter, reason, e) {
  70. // if( reason == "input-request" ){
  71. // }
  72. //}.bind(this));
  73. fsm.when('modal -> normal', function(exit, enter, reason, e) {
  74. if (reason == 'import-text-finish') {
  75. this.receiver.element.focus();
  76. }
  77. }.bind(this));
  78. },
  79. dispatch: function(e){
  80. if( this.nodeMenu.isActive ){
  81. var handleResult = this.nodeMenu.dispatchKey(e);
  82. if (handleResult) {
  83. return true;
  84. e.preventDefault();
  85. } else {
  86. this.minder.dispatchKeyEvent(e);
  87. }
  88. }
  89. //console.log( e.key );
  90. return false;
  91. },
  92. active : function( type, position ){
  93. if( type == "main" ){
  94. this.nodeMenu.targetCoordinates = {
  95. top: parseInt( position.y + this.editor.Content_Offset_Top ),
  96. left: position.x,
  97. width: 1,
  98. height: 1,
  99. right: position.x+1,
  100. bottom: parseInt( position.y ) + this.editor.Content_Offset_Top + 1
  101. };
  102. this.nodeMenu.load();
  103. this.nodeMenu.checkStatus();
  104. }else{
  105. this.nodeMenu.hide();
  106. }
  107. },
  108. state : function(){
  109. return this.nodeMenu.state;
  110. },
  111. load: function (callback) {
  112. },
  113. destroy: function () {
  114. this.node.destroy();
  115. delete this;
  116. }
  117. });
  118. Popmenu.STATE_IDLE = "idle";
  119. MWF.xApplication.MinderEditor.NodePopMenu = new Class({
  120. Extends: MTooltips,
  121. options : {
  122. axis: "x", //箭头在x轴还是y轴上展现
  123. position : { //node 固定的位置
  124. x : "auto", //x轴上left center right, auto 系统自动计算
  125. y : "bottom" //y 轴上top middle bottom, auto 系统自动计算
  126. },
  127. priorityOfAuto :{
  128. x : [ "right", "left" ], //当position x 为 auto 时候的优先级
  129. y : [ "bottom", "middle", "top" ] //当position y 为 auto 时候的优先级
  130. },
  131. event : "mouseenter", //事件类型,有target 时有效, mouseenter对应mouseleave,click 对应 container 的 click
  132. hasArrow : false,
  133. isAutoHide : false
  134. },
  135. load: function(){
  136. this.fireEvent("queryLoad",[this]);
  137. if( this.isEnable() ){
  138. if( this.node ){
  139. this.show();
  140. }else{
  141. this.create();
  142. }
  143. }
  144. this.stat = "main";
  145. this.fireEvent("postLoad",[this]);
  146. },
  147. hide: function(){
  148. if( this.node ){
  149. this.node.setStyle("display","none");
  150. this.status = "hidden";
  151. if( this.maskNode ){
  152. this.maskNode.setStyle("display","none");
  153. }
  154. if( this.commands.activeTooltip ){
  155. this.commands.activeTooltip.hide();
  156. }
  157. this.fireEvent("hide",[this]);
  158. }
  159. },
  160. _customNode : function( node, contentNode ){
  161. this.itemNodeList = [];
  162. this.itemNodeObject = {};
  163. this.availableCommands = ["appendChild","appendParent","appendSibling","arrangeUp","arrangeDown",
  164. "edit","remove","hyperLink","image","priority","progress"
  165. //"clearstyle","copystyle","pastestyle","fontfamily","fontsize","bold","forecolor","background",
  166. //"selectAll"
  167. ];
  168. this.commands = new MWF.xApplication.MinderEditor.Commands( this.app , {
  169. type : "popmenu",
  170. onPostExecCommand: function( commandsObj, command ){
  171. this.state = "idle";
  172. this.hide();
  173. }.bind( this )
  174. });
  175. this.commands.selectOptions = {
  176. //"style" : "minderPopmenu",
  177. "tooltipsOptions": {
  178. axis: "x", //箭头在x轴还是y轴上展现
  179. position : { //node 固定的位置
  180. x : "auto", //x轴上left center right, auto 系统自动计算
  181. y : "auto" //y 轴上top middle bottom, auto 系统自动计算
  182. },
  183. priorityOfAuto :{
  184. x : [ "right", "left" ], //当position x 为 auto 时候的优先级
  185. y : [ "bottom" ] //当position y 为 auto 时候的优先级
  186. },
  187. event : "mouseenter", //事件类型,有target 时有效, mouseenter对应mouseleave,click 对应 container 的 click
  188. hiddenDelay : 200, //ms , 有target 且 事件类型为 mouseenter 时有效
  189. displayDelay : 0, //ms , 有target 且事件类型为 mouseenter 时有效
  190. "onQueryLoad": function (tooltips) {
  191. if (tooltips.selector.command && this.commands.commands) {
  192. tooltips.disable = this.commands.commands[tooltips.selector.command].disable();
  193. }
  194. }.bind(this),
  195. "onPostLoad": function (tooltips) {
  196. this.commands.activeTooltip = tooltips;
  197. }.bind(this),
  198. "onHide": function (tooltips) {
  199. if (this.commands.activeTooltip == tooltips)this.commands.activeTooltip = null;
  200. }.bind(this),
  201. event: "mouseenter" //事件类型,有target 时有效, mouseenter对应mouseleave,click 对应 container 的 click
  202. }
  203. };
  204. contentNode.addEvent('contextmenu', function(e) {
  205. e.preventDefault();
  206. });
  207. this.createItemList( contentNode );
  208. this.state = "idle";
  209. //
  210. //this.minder.on('interactchange', function() {
  211. // this.hide();
  212. //}.bind(this));
  213. },
  214. createItemList:function(node){
  215. var _popmenu = this.popmenu;
  216. this.css = _popmenu.css;
  217. this.listContentNode = new Element("div.listContentNode",{
  218. "styles":this.css.listContentNode
  219. }).inject( node );
  220. this.listNode = new Element("div.listNode",{
  221. "styles":this.css.listNode
  222. }).inject(this.listContentNode);
  223. var commands = this.commands.commands;
  224. this.availableCommands.each( function( name ){
  225. if( commands[name] ){
  226. this.createItem( commands[name], name );
  227. }
  228. }.bind(this));
  229. },
  230. createItem: function( command, name ){
  231. var _self = this;
  232. var node = new Element("div.listItemNode",{
  233. "text" : command.locale || null
  234. }).inject(this.listNode);
  235. var keyNode = new Element("div.listItemKeyNode", {
  236. "styles" : this.css.listItemKeyNode,
  237. "text" : typeOf( command.key ) == "array" ? command.key.join(",") : (command.key || "")
  238. }).inject(node);
  239. node.keyNode = keyNode;
  240. this.setNormalStye( node, keyNode, command );
  241. if( command.disable() ){
  242. this.setDisableStye( node, keyNode, command )
  243. }
  244. var title = (command.title || ""); //+ ( command.key ? (" 快捷键:" + command.key) : "" );
  245. node.set("title", title);
  246. node.addEvents({
  247. mouseover : function(){
  248. if( !command.disable() ){
  249. this.setActiveStye( node, keyNode, command )
  250. }else{
  251. this.setDisableStye( node, keyNode, command )
  252. }
  253. }.bind(this),
  254. mouseout : function(){
  255. if( !command.disable() ) {
  256. this.setNormalStye( node, keyNode, command )
  257. }else{
  258. this.setDisableStye( node, keyNode, command )
  259. }
  260. }.bind(this)
  261. });
  262. if( command.action ){
  263. node.addEvent("click", function( ev ){
  264. if( !command.disable() ) {
  265. command.action();
  266. _self.checkStatus();
  267. _self.state = "idle";
  268. _self.hide();
  269. _self.fireEvent( "postExecCommand", [_self.commands, command ] );
  270. ev.stopPropagation();
  271. }
  272. }.bind(name))
  273. }
  274. if( command.init ){
  275. command.init( node, name );
  276. }
  277. this.itemNodeList.push( node );
  278. this.itemNodeObject[ name ] = node;
  279. },
  280. setDisableStye : function( node,keyNode, command ){
  281. node.setStyles( this.css.listItemNode_disable );
  282. keyNode.setStyles( this.css.listItemKeyNode_disable );
  283. if( command.icon ){
  284. node.setStyle( "background-image" , "url(../x_component_MinderEditor/$Main/"+ this.popmenu.options.style +"/icon/"+command.icon+"_disable.png)" );
  285. }
  286. },
  287. setActiveStye : function( node, keyNode, command ){
  288. node.setStyles( this.css.listItemNode_over );
  289. keyNode.setStyles( this.css.listItemKeyNode_over );
  290. if( command.icon ) {
  291. node.setStyle("background-image", "url(../x_component_MinderEditor/$Main/" + this.popmenu.options.style + "/icon/" + command.icon + "_menu.png)")
  292. }
  293. },
  294. setNormalStye : function( node, keyNode, command ){
  295. node.setStyles(this.css.listItemNode);
  296. keyNode.setStyles( this.css.listItemKeyNode );
  297. if( command.icon ) {
  298. node.setStyle("background-image", "url(../x_component_MinderEditor/$Main/" + this.popmenu.options.style + "/icon/" + command.icon + "_normal.png)")
  299. }
  300. },
  301. checkStatus : function(){
  302. for( var name in this.itemNodeObject ){
  303. var node = this.itemNodeObject[name];
  304. if( this.commands.commands[ name ] ){
  305. var command = this.commands.commands[ name ];
  306. if( command.disable() ){
  307. this.setDisableStye( node, node.keyNode, command )
  308. }else{
  309. this.setNormalStye( node, node.keyNode, command )
  310. }
  311. }
  312. }
  313. },
  314. dispatchKey : function( e ){
  315. var key = this.commands.getKey( e );
  316. var command = this.commands.keyCommands[ key ];
  317. if( command && !command.disable() && this.itemNodeObject[command.name]){
  318. if( command.action ){
  319. command.action();
  320. this.checkStatus();
  321. this.state = "idle";
  322. this.commands.fireEvent( "postExecCommand", [ this.commands, command] );
  323. return true;
  324. }else if( command.keyAction ){
  325. if( this.commands.activeTooltip )this.commands.activeTooltip.hide();
  326. command.keyAction();
  327. this.state = "expand";
  328. return true;
  329. }else{
  330. this.state = "main";
  331. return true;
  332. }
  333. }
  334. var defaultCommand = this.commands.defaultKeyCommands[ key ];
  335. if( defaultCommand && !defaultCommand.disable() && this.itemNodeObject[defaultCommand.name] ){
  336. this.state = "idle";
  337. return false
  338. }
  339. this.state = "main";
  340. return true;
  341. }
  342. //dispatchKey : function( e, callback ){
  343. // var key = e.key;
  344. // if( e.shiftKey && e.keyCode != 16 ){
  345. // key = "Shift + " + e.key.capitalize();
  346. // }
  347. // if( e.ctrlKey && e.keyCode != 17 ){
  348. // key = "Ctrl + " + e.key.capitalize();
  349. // }
  350. // if( e.altKey && e.keyCode != 18 ){
  351. // key = "Alt + " + e.key.capitalize();
  352. // }
  353. // var node = this.keyObject[ key ];
  354. // if( node ){
  355. // node.click( e );
  356. // this.hide();
  357. // if(callback)callback( e, true );
  358. // return true;
  359. // }else{
  360. // if(callback)callback( e, false );
  361. // return false;
  362. // }
  363. //}
  364. });