Visual editor: editing meta data via contenteditable instead of inputs
[fnpeditor.git] / modules / visualEditor.js
1 rng.modules.visualEditor = function(sandbox) {\r
2     var transformations = rng.modules.visualEditor.transformations;\r
3 \r
4     var view = {\r
5         node: $(sandbox.getTemplate('main')()),\r
6         setup: function() {\r
7             var view = this;\r
8
9             this.node.find('#rng-visualEditor-content').on('keyup', function() {\r
10                 isDirty = true;\r
11             });\r
12             \r
13             this.node.find('#rng-visualEditor-meta').on('keyup', function() {\r
14                 isDirty = true;\r
15             });\r
16
17             this.node.on('mouseover', '[wlxml-tag]', function(e) { $(e.target).addClass('rng-hover')});\r
18             this.node.on('mouseout', '[wlxml-tag]', function(e) { $(e.target).removeClass('rng-hover')});\r
19             this.node.on('click', '[wlxml-tag]', function(e) {\r
20                 console.log('clicked node type: '+e.target.nodeType);\r
21                 view._markSelected($(e.target));\r
22             });\r
23 \r
24             this.node.on('keyup', '#rng-visualEditor-contentWrapper', function(e) {\r
25                 var anchor = $(window.getSelection().anchorNode);\r
26                 if(anchor[0].nodeType === Node.TEXT_NODE)\r
27                     anchor = anchor.parent();\r
28                 if(!anchor.is('[wlxml-tag]'))\r
29                     return;\r
30                 view._markSelected(anchor);\r
31             });\r
32             \r
33             \r
34             var metaTable = this.metaTable = this.node.find('#rng-visualEditor-meta table');\r
35             \r
36             this.metaTable.find('.rng-visualEditor-metaAddBtn').click(function() {\r
37                 var newRow = view._addMetaRow('', '');\r
38                 $(newRow.find('td div')[0]).focus();\r
39                 isDirty = true;\r
40             });\r
41             \r
42             this.metaTable.on('click', '.rng-visualEditor-metaRemoveBtn', function(e) {\r
43                 $(e.target).closest('tr').remove();\r
44                 isDirty = true;\r
45             });\r
46             \r
47             this.metaTable.on('keydown', '[contenteditable]', function(e) {\r
48                 console.log(e.which);\r
49                 if(e.which === 13) { \r
50                     if($('*:focus').hasClass('rng-visualEditor-metaItemKey')) {\r
51                         metaTable.find('.rng-visualEditor-metaItemValue').focus();\r
52                     } else {\r
53                         var input = $('<input>');\r
54                         input.appendTo('body').focus()\r
55                         metaTable.find('.rng-visualEditor-metaAddBtn').focus();\r
56                         input.remove();\r
57                     }\r
58                     e.preventDefault();\r
59                 }\r
60                 \r
61             });\r
62
63         },\r
64         getMetaData: function() {\r
65             var toret = {};\r
66             this.metaTable.find('tr').not('.rng-visualEditor-addMetaRow').each(function() {\r
67                 var tr = $(this);\r
68                 var inputs = $(this).find('td [contenteditable]');\r
69                 var key = $(inputs[0]).text();\r
70                 var value = $(inputs[1]).text();\r
71                 toret[key] = value;\r
72             });\r
73             console.log(toret);\r
74             return toret;\r
75         },\r
76         setMetaData: function(metadata) {\r
77             var view = this;\r
78             this.metaTable.find('tr').not('.rng-visualEditor-addMetaRow').remove();\r
79             _.each(_.keys(metadata), function(key) {    \r
80                 view._addMetaRow(key, metadata[key]);\r
81             });\r
82         },\r
83         setBody: function(HTMLTree) {\r
84             this.node.find('#rng-visualEditor-content').html(HTMLTree);\r
85         },\r
86         getBody: function() {\r
87             return this.node.find('#rng-visualEditor-content').html();\r
88         }, \r
89         _markSelected: function(node) {\r
90             this.node.find('.rng-current').removeClass('rng-current');\r
91             node.addClass('rng-current');\r
92         },\r
93         _addMetaRow: function(key, value) {\r
94             var addRow = this.metaTable.find('.rng-visualEditor-addMetaRow');\r
95             var newRow = $(sandbox.getTemplate('metaItem')({key: key || '', value: value || ''}));\r
96             newRow.insertBefore(addRow);\r
97             return newRow;\r
98         }\r
99     };\r
100     view.setup();\r
101     \r
102     var isDirty = false;\r
103     \r
104     \r
105     return {\r
106         start: function() {\r
107             sandbox.publish('ready');\r
108         },\r
109         getView: function() {\r
110             return view.node;\r
111         },\r
112         setDocument: function(xml) {\r
113             var transformed = transformations.fromXML.getDocumentDescription(xml);\r
114             view.setBody(transformed.HTMLTree);\r
115             view.setMetaData(transformed.metadata);\r
116             isDirty = false;\r
117         },\r
118         getDocument: function() {\r
119             return transformations.toXML.getXML({HTMLTree: view.getBody(), metadata: view.getMetaData()});\r
120         },\r
121         isDirty: function() {\r
122             return isDirty;\r
123         },\r
124         setDirty: function(dirty) {\r
125             isDirty = dirty;\r
126         }\r
127     \r
128     }\r
129 };