Visual editor: selecting first node on first display
[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.node.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($(document.activeElement).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                         view.node.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').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').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             mediator.nodeSelected(node);\r
93         },\r
94         markFirstSelected: function() {\r
95             var firstNodeWithText = this.node.find('[wlxml-tag]').filter(function() {\r
96                 return $(this).clone().children().remove().end().text().trim() !== '';\r
97             }).first();\r
98             if(firstNodeWithText.length)\r
99                 $(firstNodeWithText[0]).click().focus();\r
100         },\r
101         _addMetaRow: function(key, value) {\r
102             var newRow = $(sandbox.getTemplate('metaItem')({key: key || '', value: value || ''}));\r
103             newRow.appendTo(this.metaTable);\r
104             return newRow;\r
105         }\r
106     };\r
107     \r
108     \r
109     var sideBarView = {\r
110         node: view.node.find('#rng-visualEditor-sidebar'),\r
111         setup: function() {\r
112             var view = this;\r
113             this.node.find('#rng-visualEditor-sidebarButtons a').click(function(e) {\r
114                 e.preventDefault();\r
115                 var target = $(e.currentTarget);\r
116                 if(!target.attr('data-content-id'))\r
117                     return;\r
118                 view.selectTab(target.attr('data-content-id'));\r
119             });\r
120             view.selectTab('rng-visualEditor-edit');\r
121         },\r
122         selectTab: function(id) {\r
123            this.node.find('.rng-visualEditor-sidebarContentItem').hide();\r
124            this.node.find('#'+id).show();\r
125            this.node.find('#rng-visualEditor-sidebarButtons li').removeClass('active');\r
126            this.node.find('#rng-visualEditor-sidebarButtons li a[data-content-id=' + id + ']').parent().addClass('active');\r
127         \r
128         },\r
129         updateEditPane: function(node) {\r
130             var pane = this.node.find('#rng-visualEditor-edit');\r
131             pane.html( $(sandbox.getTemplate('editPane')({tag: node.attr('wlxml-tag'), klass: node.attr('wlxml-class')})));\r
132         }\r
133     }\r
134     \r
135     view.setup();\r
136     sideBarView.setup();\r
137     \r
138     var mediator = {\r
139         nodeSelected: function(node) {\r
140             sideBarView.updateEditPane(node);\r
141         }\r
142     }\r
143     \r
144     var isDirty = false;\r
145     var wasShownAlready = false;\r
146     \r
147     \r
148     return {\r
149         start: function() {\r
150             sandbox.publish('ready');\r
151         },\r
152         getView: function() {\r
153             return view.node;\r
154         },\r
155         setDocument: function(xml) {\r
156             var transformed = transformations.fromXML.getDocumentDescription(xml);\r
157             view.setBody(transformed.HTMLTree);\r
158             view.setMetaData(transformed.metadata);\r
159             isDirty = false;\r
160         },\r
161         getDocument: function() {\r
162             return transformations.toXML.getXML({HTMLTree: view.getBody(), metadata: view.getMetaData()});\r
163         },\r
164         isDirty: function() {\r
165             return isDirty;\r
166         },\r
167         setDirty: function(dirty) {\r
168             isDirty = dirty;\r
169         },\r
170         onShowed: function() {\r
171             if(!wasShownAlready) {\r
172                 wasShownAlready = true;\r
173                 view.markFirstSelected();\r
174             }\r
175         }\r
176     \r
177     }\r
178 };