PageRenderTime 66ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

/app/app.js

https://bitbucket.org/ferenc_radius/mindmap_collaboration
JavaScript | 1048 lines | 519 code | 135 blank | 394 comment | 51 complexity | 232eeaa8a8833f6cda2573396841e1f7 MD5 | raw file
  1. jQuery(function($) {
  2. /*======================================================================================================================
  3. * NODE_STATES
  4. *
  5. *======================================================================================================================
  6. *
  7. * Enum Node states
  8. */
  9. var NODE_STATES = {
  10. DEFAULT: "default",
  11. EDIT: "edit",
  12. SELECTED: "selected",
  13. ADDCHILD: "addchild",
  14. DRAGGING: "dragging",
  15. COLLIDED: "collided"
  16. };
  17. /**
  18. /*======================================================================================================================
  19. * MindMapNode
  20. *
  21. *======================================================================================================================
  22. *
  23. * @class MindMapNode
  24. */
  25. var MindMapNode = Backbone.Model.extend({
  26. defaults: {
  27. content: "Nieuwe Node",
  28. pointX: 100,
  29. pointY: 100,
  30. parentNode: null,
  31. userId: null,
  32. state: NODE_STATES.DEFAULT,
  33. width: null,
  34. height: null
  35. },
  36. children: null,
  37. /**
  38. * @constructor
  39. * @method initialize
  40. */
  41. initialize: function()
  42. {
  43. this.children = new MindMapNodeList();
  44. },
  45. /**
  46. * Has this or any of its children the given states
  47. *
  48. * @param states NODE_STATE[]
  49. * @method haveStates
  50. */
  51. haveStates: function(states)
  52. {
  53. if( states.indexOf(this.get("state")) > -1 )
  54. {
  55. return true;
  56. }
  57. var i = this.children.length;
  58. while (i--)
  59. {
  60. var haveStates = this.children.at(i).haveStates(states);
  61. if (haveStates)
  62. {
  63. return haveStates;
  64. }
  65. }
  66. return false;
  67. },
  68. /**
  69. * Those node intersect other node ?
  70. *
  71. * Will return null when nothing is found.
  72. *
  73. * @param {MindMapNode} node
  74. * @method intersect
  75. * @return MindMapNode[]
  76. */
  77. intersect: function(node)
  78. {
  79. var intersected = [];
  80. // target lookup coordinates
  81. var targetLeft = node.get("pointX");
  82. var targetRight = targetLeft + node.get("width");
  83. var targetTop = node.get("pointY");
  84. var targetBottom = targetTop + node.get("height");
  85. // current node lookup coordinates
  86. var left = this.get("pointX");
  87. var right = left + this.get("width");
  88. var top = this.get("pointY");
  89. var bottom = top + this.get("height");
  90. // compare coordinates from target with current if they intersect,
  91. // the node should not be intersecting with itself.
  92. if (left <= targetRight && targetLeft <= right && top <= targetBottom && targetTop <= bottom && this != node)
  93. {
  94. intersected.push(this);
  95. }
  96. // foreach child if child = this x and i
  97. var i = this.children.length;
  98. while (i--)
  99. {
  100. var tmp = this.children.at(i).intersect(node);
  101. if (tmp != null)
  102. {
  103. intersected = intersected.concat(tmp);
  104. }
  105. }
  106. return intersected;
  107. },
  108. /**
  109. * Draw lines to other node.
  110. *
  111. * @param drawMethod Function callback
  112. * @param {int} x2 optional target x position
  113. * @param {int} y2 optional target y position
  114. * @method linesToChildren
  115. */
  116. linesToChildren: function(drawMethod, x2, y2)
  117. {
  118. var x = this.get("pointX") + (this.get("width") /2);
  119. var y = this.get("pointY") + (this.get("height") /2);
  120. if( x2 && y2)
  121. {
  122. drawMethod(x, y, x2, y2);
  123. }
  124. this.children.each(function(node) {
  125. // calc positions of child.
  126. var x2 = node.get("pointX") + (node.get("width") / 2);
  127. var y2 = node.get("pointY") + (node.get("height") / 2);
  128. // draw line
  129. drawMethod(x, y, x2, y2);
  130. node.children.each(function(node) {
  131. node.linesToChildren(drawMethod, x2, y2);
  132. });
  133. });
  134. },
  135. /**
  136. * Find all parents of this node
  137. *
  138. * @return MindMapNode[]
  139. */
  140. getParents: function()
  141. {
  142. var parents = [];
  143. if( this.get("parentNode") != null)
  144. {
  145. parents.push(this.get("parentNode"));
  146. parents = parents.concat(this.get("parentNode").getParents());
  147. }
  148. return parents;
  149. },
  150. /**
  151. * Is given node a child of this node.
  152. *
  153. * @param {MindMapNode} parent the parent node
  154. * @method isChild
  155. */
  156. isChildOf: function(parent)
  157. {
  158. var res = this.children.select(function(node) {
  159. return node.cid == parent.cid;
  160. });
  161. return res.length > 0;
  162. },
  163. /**
  164. * Find the nearest common ancestor of this and given node.
  165. *
  166. * @param node MindMapNode
  167. * @method hasCommonAncestor
  168. * @return MindMapNode|null
  169. */
  170. findCommonAncestor: function(node)
  171. {
  172. var parents = this.getParents();
  173. var parents2 = node.getParents();
  174. var found = null;
  175. for(var i = 0, j = parents.length; i < j && found == null; i++ )
  176. {
  177. for(var k = 0, l = parents2.length; k < l; k++)
  178. {
  179. if(parents[i].cid == parents2[k].cid)
  180. {
  181. found = parents2[k];
  182. }
  183. }
  184. }
  185. return found;
  186. }
  187. });
  188. /*======================================================================================================================
  189. * MindMapNodeList
  190. *
  191. *======================================================================================================================
  192. *
  193. *
  194. * @class MindMapNodeList
  195. */
  196. var MindMapNodeList = Backbone.Collection.extend({
  197. model: MindMapNode
  198. });
  199. /*======================================================================================================================
  200. * MindMap
  201. *
  202. *======================================================================================================================
  203. *
  204. *
  205. * @class MindMap
  206. */
  207. var MindMap = Backbone.Model.extend({
  208. root: null,
  209. /**
  210. * @method initialize
  211. */
  212. initialize: function()
  213. {
  214. this.set({"root": new MindMapNode()});
  215. }
  216. });
  217. /*======================================================================================================================
  218. * MindMapApplication
  219. *
  220. *======================================================================================================================
  221. *
  222. * MindMap application controller
  223. *
  224. * @class MindMapApplication
  225. */
  226. var MindMapApplication = Backbone.Controller.extend({
  227. routes: {
  228. "/index": "index",
  229. "/new": "run"
  230. },
  231. map: null,
  232. /**
  233. * @constructor
  234. * @method initialize
  235. */
  236. initialize: function()
  237. {
  238. this.location("/index");
  239. },
  240. /**
  241. * Open Index view
  242. * @method index
  243. */
  244. index: function()
  245. {
  246. new IndexView();
  247. },
  248. /**
  249. * Run application
  250. *
  251. * @method run
  252. */
  253. run: function()
  254. {
  255. this.map = new MindMapView({model: new MindMap()});
  256. this.map.show();
  257. this.location("/index");
  258. },
  259. /**
  260. * Set the location of the application.
  261. *
  262. * @param url
  263. * @method location
  264. */
  265. location: function(url)
  266. {
  267. location.hash = "#" + url;
  268. },
  269. /**
  270. * Delegate the collided.
  271. *
  272. * @param node
  273. * @method handleIntersects
  274. */
  275. handleIntersects: function(node)
  276. {
  277. var intersected = window.application.map.model.get("root").intersect(node);
  278. for( var i = 0, j = intersected.length; i < j; i++ )
  279. {
  280. intersected[i].set({
  281. "state": NODE_STATES.COLLIDED
  282. });
  283. }
  284. }
  285. });
  286. /*======================================================================================================================
  287. * IndexView
  288. *
  289. *======================================================================================================================
  290. *
  291. * Index view > Index page
  292. *
  293. * class IndexView
  294. */
  295. var IndexView = Backbone.View.extend({
  296. el: $("body"),
  297. events: {
  298. "click #new-map": "newMap"
  299. },
  300. /**
  301. * @method newMap
  302. */
  303. newMap: function()
  304. {
  305. application.run();
  306. }
  307. });
  308. /*======================================================================================================================
  309. * MindMapView
  310. *
  311. *======================================================================================================================
  312. *
  313. * View the mindMap (Generates the root node)
  314. *
  315. * @class MindMapView
  316. */
  317. var MindMapView = Backbone.View.extend({
  318. id: "map",
  319. /**
  320. * @method initialize
  321. */
  322. initialize: function()
  323. {
  324. var self = this;
  325. $(window).resize(function() {
  326. self.render();
  327. self.drawLinesToChildren();
  328. });
  329. },
  330. /**
  331. * Draw line on canvas
  332. *
  333. * @param {int} x
  334. * @param {int} y
  335. * @param {int} x2
  336. * @param {int} y2
  337. * @method drawLine
  338. */
  339. drawLine: function(x, y, x2, y2)
  340. {
  341. var canvas = document.getElementById("canvas");
  342. // Make sure we don't execute when canvas isn't supported
  343. if (canvas.getContext)
  344. {
  345. var ctx = canvas.getContext('2d');
  346. // draw the line
  347. ctx.beginPath();
  348. ctx.moveTo(x, y);
  349. ctx.lineTo(x2, y2);
  350. ctx.stroke();
  351. ctx.closePath();
  352. }
  353. },
  354. /**
  355. * Draw lines all children of the root element
  356. *
  357. * @method drawLinesToChildren
  358. */
  359. drawLinesToChildren: function()
  360. {
  361. var canvas = document.getElementById("canvas");
  362. // Make sure we don't execute when canvas isn't supported
  363. if (canvas.getContext)
  364. {
  365. // use getContext to use the canvas for drawing
  366. var ctx = canvas.getContext('2d');
  367. ctx.clearRect(0, 0, $(canvas).width(), $(canvas).height());
  368. // draw lines to all children of the root node
  369. this.model.get("root").linesToChildren(window.application.map.drawLine);
  370. }
  371. },
  372. /**
  373. * render root node
  374. *
  375. * @method render
  376. */
  377. render: function()
  378. {
  379. var width = $(document).width();
  380. var height = $(document).height();
  381. var canvas = document.getElementById("canvas");
  382. canvas.width = width;
  383. canvas.height = height;
  384. $(this.el).css("width", width);
  385. $(this.el).css("height", height);
  386. // render nodeView for root node.
  387. var nodeView = new MindMapNodeView({model: this.model.get("root")});
  388. // we need to append it first so the dimensions of a node are known.
  389. $(this.el).append(
  390. $(nodeView.el).addClass("root")
  391. );
  392. nodeView.render();
  393. return this;
  394. },
  395. /**
  396. * Show the mindMapView (add it to the document) by replacing the element (by id)
  397. *
  398. * @method show
  399. */
  400. show: function()
  401. {
  402. $("#" + this.id).replaceWith(this.render().el);
  403. }
  404. });
  405. /*======================================================================================================================
  406. * DraggableView
  407. *
  408. *======================================================================================================================
  409. *
  410. * Make a view draggable, by using the optional .el parameter you can make
  411. * every view a draggable view.
  412. *
  413. * This view uses jquery.ui.draggable (1.8+ tested)
  414. *
  415. * @class DraggableView
  416. */
  417. var DraggableView = Backbone.View.extend({
  418. /**
  419. * This functions is empty by default, and can be overridden by giving a callback parameter
  420. *
  421. * Will be called on Drag start.
  422. *
  423. * Callback will have arguments:
  424. * event
  425. * ui
  426. *
  427. * @method onStart
  428. * @param {Function} callback
  429. * @method onStart
  430. */
  431. onStart: function(callback)
  432. {
  433. this.onStart = callback;
  434. },
  435. /**
  436. * This functions is empty by default, and can be overridden by giving a callback parameter
  437. *
  438. * Callback will have arguments:
  439. * event
  440. * ui
  441. *
  442. * Will be called on Drag stop.
  443. *
  444. * @method onStop
  445. * @param callback Function
  446. * @method onStop
  447. */
  448. onStop: function(callback)
  449. {
  450. this.onStop = callback;
  451. },
  452. /**
  453. * This functions is empty by default, and can be overridden by giving a callback parameter
  454. *
  455. * Callback will have arguments:
  456. * event
  457. * ui
  458. *
  459. * Will be called on Drag.
  460. *
  461. * @method onDrag
  462. * @param callback Function
  463. * @method onDrag
  464. */
  465. onDrag: function(callback)
  466. {
  467. this.onDrag = callback;
  468. },
  469. /**
  470. * Stop dragging will destroy the drag functionality and call the onStop event.
  471. *
  472. * @param {Event} event
  473. * @param {Object} ui
  474. * @method stopDrag
  475. */
  476. stopDrag: function(event, ui)
  477. {
  478. this.onStop(event, ui);
  479. //remove draggable
  480. $(this.el).draggable("destroy");
  481. },
  482. /**
  483. * Render will make the element (.el) from this view draggable,
  484. * so by providing a .el option to the view it will make that element draggable.
  485. *
  486. * @method render
  487. */
  488. render: function()
  489. {
  490. // make sure the events (callbacks) are executed in the view scope.
  491. var self = this;
  492. $(this.el).draggable({
  493. stop: function(event, ui) {
  494. self.stopDrag(event, ui);
  495. },
  496. start: function(event, ui) {
  497. self.onStart(event, ui);
  498. },
  499. drag: function(event, ui) {
  500. self.onDrag(event, ui);
  501. },
  502. disabled: false,
  503. grid: [10, 10],
  504. scroll: false,
  505. snap: true
  506. });
  507. }
  508. });
  509. /*======================================================================================================================
  510. * EditableMindMapNodeView
  511. *
  512. *======================================================================================================================
  513. *
  514. * requires model argument (instance of MindMapNode)
  515. *
  516. * @class EditableMindMapNodeView
  517. */
  518. var EditableMindMapNodeView = Backbone.View.extend({
  519. tagName: "input",
  520. events: {
  521. "keypress": "keyPressInput",
  522. "blur": "stopEdit"
  523. },
  524. /**
  525. * Stop editing, will update the given model with the new value.
  526. *
  527. * @method stopEdit
  528. */
  529. stopEdit: function()
  530. {
  531. $(this.el).parent().removeClass(NODE_STATES.SELECTED);
  532. this.model.set({"content": this.getEditValue(), "state": NODE_STATES.DEFAULT});
  533. return this;
  534. },
  535. /**
  536. * Find out if enter is hit, if so then stop editing
  537. *
  538. * @param {Event} e
  539. * @method keyPressInput
  540. */
  541. keyPressInput: function(e)
  542. {
  543. // If you hit `enter`, we"re through editing the item.
  544. if (e.keyCode === 13)
  545. {
  546. this.stopEdit();
  547. }
  548. },
  549. /**
  550. * Get value edited.
  551. *
  552. * @method getEditValue
  553. * @return String
  554. */
  555. getEditValue: function()
  556. {
  557. return $(this.el).val();
  558. },
  559. /**
  560. * Render view
  561. *
  562. * @method render
  563. * @override
  564. * return EditableMindMapNodeView
  565. */
  566. render: function()
  567. {
  568. $(this.el).val(this.model.escape("content"));
  569. return this;
  570. }
  571. });
  572. /*======================================================================================================================
  573. * MindMapNodeAddButtonView
  574. *
  575. *======================================================================================================================
  576. *
  577. * MindMap add button to add a child
  578. *
  579. * @class MindMapNodeAddButtonView
  580. */
  581. var MindMapNodeAddButtonView = Backbone.View.extend({
  582. tagName: "button",
  583. events: {
  584. "click": "click"
  585. },
  586. /**
  587. * On click set state of node to 'addchild'
  588. *
  589. * @method click
  590. */
  591. click: function()
  592. {
  593. this.hide();
  594. this.model.set({"state": NODE_STATES.ADDCHILD});
  595. },
  596. /**
  597. * Show the button
  598. *
  599. * @method show
  600. */
  601. show: function()
  602. {
  603. if( this.isShown() )
  604. {
  605. return;
  606. }
  607. $(this.render().el).fadeIn(250);
  608. // hide button after timeout
  609. var self = this;
  610. setTimeout(function() {
  611. self.hide();
  612. }, 2000);
  613. },
  614. /**
  615. * Hide the button
  616. *
  617. * @param [timeout] default 250
  618. * @method hide
  619. */
  620. hide: function(timeout)
  621. {
  622. $(this.el).fadeOut(timeout || 250);
  623. },
  624. /**
  625. * Is button shown?
  626. *
  627. * @method isShown
  628. * @return String
  629. */
  630. isShown: function()
  631. {
  632. return $(this.el).is(":visible");
  633. },
  634. /**
  635. * View render method appends the button the the body
  636. *
  637. * @method render
  638. * @return MindMapNodeAddButtonView
  639. */
  640. render: function()
  641. {
  642. $(this.el)
  643. .css({
  644. position: 'absolute',
  645. top: this.model.get("pointY") + "px",
  646. left: (this.model.get("pointX") + this.model.get("width") + 10) + "px",
  647. display: "none"
  648. }).text("+").appendTo('body');
  649. return this;
  650. }
  651. });
  652. /*======================================================================================================================
  653. * MindMapNodeView
  654. *
  655. *======================================================================================================================
  656. *
  657. * MindMapNode
  658. *
  659. * @class EditableMindMapNodeView
  660. */
  661. var MindMapNodeView = Backbone.View.extend({
  662. className: "node",
  663. events: {
  664. "click": "click",
  665. "dblclick": "doubleClick",
  666. "mouseover": "mouseOver"
  667. },
  668. /**
  669. * subviews
  670. */
  671. addButtonView: null,
  672. editView: null,
  673. /**
  674. * @constructor
  675. * @method initialize
  676. */
  677. initialize: function()
  678. {
  679. var self = this;
  680. // render when model is changed
  681. this.model.bind("change", function()
  682. {
  683. if(this.hasChanged("pointX") || this.hasChanged("pointY"))
  684. {
  685. // find new coalitions
  686. if(this.get("state") != NODE_STATES.DRAGGING)
  687. {
  688. window.application.handleIntersects(this);
  689. }
  690. self.render.call(self);
  691. }
  692. else if (this.hasChanged("content"))
  693. {
  694. self.render.call(self);
  695. }
  696. else if ( this.hasChanged("state") )
  697. {
  698. self.handleState(self.model.get("state"));
  699. }
  700. });
  701. // keys
  702. $(document).keydown(function(e) {
  703. if( $(self.el).hasClass(NODE_STATES.SELECTED) ) // only allow f2 when node is selected.
  704. {
  705. if (e.which == 113) // F2
  706. {
  707. self.model.set({"state": NODE_STATES.EDIT});
  708. }
  709. }
  710. });
  711. },
  712. /**
  713. * Hide add button view
  714. *
  715. * @param timeout
  716. * @method hideAddButton
  717. */
  718. hideAddButton: function(timeout)
  719. {
  720. if( this.addButtonView != null )
  721. {
  722. this.addButtonView.hide(timeout);
  723. }
  724. },
  725. /**
  726. * Mouse over event handler
  727. *
  728. * handles the add new node button.
  729. * @method mouseOver
  730. */
  731. mouseOver: function()
  732. {
  733. // When one node has state edit or dragging then don't add any add button view
  734. if (window.application.map.model.get("root").haveStates([NODE_STATES.EDIT, NODE_STATES.DRAGGING]))
  735. {
  736. return;
  737. }
  738. //make sure the dimensions of this view are set.
  739. this.setDimensions();
  740. // create a button and show it.
  741. if( this.addButtonView == null )
  742. {
  743. this.addButtonView = new MindMapNodeAddButtonView({model: this.model});
  744. this.addButtonView.render();
  745. }
  746. this.addButtonView.show();
  747. },
  748. /**
  749. * Click event handler
  750. *
  751. * On click this node will be made draggable.
  752. *
  753. * @method click
  754. */
  755. click: function()
  756. {
  757. if (this.model.get("state") == NODE_STATES.EDIT) // don't do mouse move stuff when editing.)
  758. {
  759. return;
  760. }
  761. $(this.el).addClass(NODE_STATES.SELECTED);
  762. this.makeDraggable();
  763. },
  764. /**
  765. * Make Node draggable by using a draggableView
  766. *
  767. * @method makeDraggable
  768. */
  769. makeDraggable: function()
  770. {
  771. // make dragView of the node
  772. var self = this;
  773. var dragView = new DraggableView({el: this.el});
  774. dragView.onStart(function() {
  775. self.model.set({"state": NODE_STATES.DRAGGING});
  776. });
  777. dragView.onStop(function() {
  778. self.model.set({"state": NODE_STATES.DEFAULT});
  779. window.application.handleIntersects(self.model);
  780. });
  781. dragView.onDrag(function(e, ui) {
  782. self.model.set({
  783. "state": NODE_STATES.DRAGGING,
  784. "pointX": ui.position.left,
  785. "pointY": ui.position.top
  786. });
  787. });
  788. dragView.render();
  789. },
  790. /**
  791. * Double click event handler
  792. *
  793. * Turn edit mode on.
  794. *
  795. * @method doubleClick
  796. */
  797. doubleClick: function()
  798. {
  799. this.model.set({"state": NODE_STATES.EDIT});
  800. },
  801. /**
  802. * Handles node state
  803. *
  804. * @method handleState
  805. * @param state NODE_STATES property of 'enum'
  806. */
  807. handleState: function(state)
  808. {
  809. switch(state)
  810. {
  811. case NODE_STATES.ADDCHILD:
  812. var node = new MindMapNode();
  813. var pointX = this.model.get("pointX") + this.model.get("width") + 50;
  814. var pointY = this.model.get("pointY");
  815. var lastNode = this.model.children.last();
  816. if( lastNode !== undefined )
  817. {
  818. pointX = lastNode.get("pointX");
  819. pointY = lastNode.get("pointY") + lastNode.get("height") + 10;
  820. }
  821. node.set({
  822. "content": "child: " + this.model.cid + " " + this.model.children.length,
  823. "pointX": pointX,
  824. "pointY": pointY,
  825. "parentNode": this.model
  826. });
  827. var nodeView = new MindMapNodeView({model: node});
  828. // we need to append it first so the dimensions of a node are known.
  829. $(window.application.map.el).append(nodeView.el);
  830. nodeView.render();
  831. // we add the node as child after it is rendered so coalition detection can be done.
  832. this.model.children.add(node);
  833. // handle intersects
  834. window.application.handleIntersects(node);
  835. // we need to paint it again after handleIntersect could have changed any positions of it's children.
  836. nodeView.render();
  837. this.model.set({"state": NODE_STATES.DEFAULT});
  838. break;
  839. case NODE_STATES.EDIT:
  840. this.editView = new EditableMindMapNodeView({model: this.model});
  841. $(this.el).html(this.editView.render().el);
  842. $(this.editView.el).focus();
  843. break;
  844. case NODE_STATES.DRAGGING:
  845. // dragging stop editing.
  846. if( this.editView != null)
  847. {
  848. this.editView.stopEdit().remove();
  849. }
  850. // remove add button on dragging
  851. this.hideAddButton(0);
  852. break;
  853. case NODE_STATES.COLLIDED:
  854. var intersects = window.application.map.model.get("root").intersect(this.model);
  855. if (intersects.length > 0)
  856. {
  857. console.log(this.model.isChildOf(intersects[0]));
  858. console.log(this.model.findCommonAncestor(intersects[0]));
  859. intersects[0].set({
  860. "state": NODE_STATES.DEFAULT,
  861. "pointX": this.model.get("pointX"),
  862. "pointY": this.model.get("pointY") + this.model.get("height") + 10
  863. });
  864. }
  865. else
  866. {
  867. this.model.set({"state": NODE_STATES.DEFAULT});
  868. }
  869. break;
  870. case NODE_STATES.DEFAULT:
  871. this.render();
  872. break;
  873. }
  874. },
  875. /**
  876. * Sets the dimensions on of the node on the model, this doesn't trigger a model change event.
  877. *
  878. * @method setDimensions
  879. */
  880. setDimensions: function()
  881. {
  882. // save the new dimensions of the node.
  883. this.model.set({
  884. 'width': $(this.el).outerWidth(),
  885. 'height': $(this.el).outerHeight()
  886. }, {silent: true});
  887. },
  888. /**
  889. * Renders the position and content of the node. (Will reset every change in the node content)
  890. *
  891. * @method render
  892. * @return MindMapNodeView
  893. */
  894. render: function()
  895. {
  896. // generate positioned node
  897. $(this.el)
  898. .attr("id", this.model.cid)
  899. .css({
  900. top: this.model.get("pointY") + "px",
  901. left: this.model.get("pointX") + "px"
  902. })
  903. .html(this.model.escape("content"));
  904. //make sure the dimensions of this view are set.
  905. this.setDimensions();
  906. // draw lines between children.
  907. window.application.map.drawLinesToChildren();
  908. return this;
  909. }
  910. });
  911. window.application = new MindMapApplication();
  912. Backbone.history.start();
  913. });