4 /* globals gettext, interpolate */
7 var getBoundariesForAList = function(fragment) {
10 if(fragment instanceof fragment.RangeFragment && fragment.hasSiblingBoundaries()) {
11 return fragment.startNode.hasSameContextRoot(fragment.endNode) && fragment.boundariesSiblingParents();
13 if(fragment instanceof fragment.NodeFragment) {
14 node = fragment.node.getNearestElementNode();
15 if(node.isContextRoot()) {
26 var countItems = function(boundaries) {
27 var ptr = boundaries.node1,
29 while(ptr && !ptr.sameNode(boundaries.node2)) {
36 var toggleListAction = function(type) {
39 add: function(callback, params) {
40 var boundaries = getBoundariesForAList(params.fragment),
41 listParams = {klass: type === 'Bullet' ? 'list' : 'list.enum'},
44 if(boundaries && boundaries.node1) {
45 boundaries.node1.document.transaction(function() {
46 var iterNode = boundaries.node1;
48 if(!iterNode.is({tagName: 'div', klass: 'p'})) {
49 if(iterNode.is({tagName: 'header'})) {
50 var newNode = iterNode.setTag('div');
51 newNode.setClass('p');
52 if(iterNode.sameNode(boundaries.node1)) {
53 boundaries.node1 = newNode;
55 if(iterNode.sameNode(boundaries.node2)) {
56 boundaries.node2 = newNode;
60 throw new Error('Invalid element');
63 if(iterNode.sameNode(boundaries.node2))
65 iterNode = iterNode.next();
67 listParams.node1 = boundaries.node1;
68 listParams.node2 = boundaries.node2;
69 var list = boundaries.node1.document.createList(listParams),
70 item1 = list.object.getItem(0),
71 text = item1 ? item1.contents()[0] : undefined, //
72 doc = boundaries.node1.document;
74 return doc.createFragment(doc.CaretFragment, {node: text, offset:0});
78 description: action.getState().description,
79 fragment: params.fragment
84 throw new Error('Invalid boundaries');
87 remove: function(callback, params) {
89 var current = params.fragment.node,
92 if(current.parent().is('item') && current.parent().parent().is('list') && current.parent().next() === null) {
93 var item = current.parent();
94 var list = item.parent();
95 var doc = current.document;
96 doc.transaction(function() {
97 var p = list.after({tagName: 'div', attrs: {'class': 'p'}});
98 p.append({text: current.getText()});
100 if(list.contents().length === 0) {
103 return doc.createFragment(
104 doc.CaretFragment, {node: p.contents()[0], offset: params.fragment.offset});
107 description: action.getState().description,
108 fragment: params.fragment
115 var toSearch = current.nodeType === Node.ELEMENT_NODE ? [current] : [];
116 toSearch = toSearch.concat(current.parents());
117 toSearch.some(function(node) {
118 var doc = node.document;
119 if(node.is('list')) {
120 doc.transaction(function() {
121 var firstItem = node.object.extractListItems(),
123 if(params.fragment.isValid()) {
124 toret = params.fragment;
126 toret = doc.createFragment(doc.NodeFragment, {node: firstItem});
131 description: action.getState().description,
132 fragment: params.fragment
137 return true; // break
141 changeType: function(callback, params) {
142 var node = params.fragment.node,
144 node.document.transaction(function() {
145 var list = node.getParent('list');
146 list.setClass(type === 'Bullet' ? 'list' : 'list.enum');
147 if(params.fragment.isValid()) {
148 return params.fragment;
150 return node.document.createFragment(node.document.NodeFragment, {node: list.contents()[0]});
154 description: action.getState().description,
155 fragment: params.fragment
162 var isToggled = function(params) {
163 if(params.fragment && params.fragment.node && params.fragment.node.isInside('list')) {
164 var list = params.fragment.node.getParent('list');
165 return list.getClass() === (type === 'Bullet' ? 'list' : 'list.enum');
170 var label = type === 'Bullet' ? gettext('bull. list') : gettext('num. list');
173 name: 'toggle' + type + 'List',
174 context: ['fragment'],
176 fragment: {type: 'context', name: 'fragment'}
181 getState: function(params) {
182 if(!params.fragment || !params.fragment.isValid()) {
186 if(params.fragment instanceof params.fragment.CaretFragment && params.fragment.node.isInside('list')) {
187 var list = params.fragment.node.getParent('list');
188 if((list.getClass() === 'list' && type === 'Enum') || (list.getClass() === 'list.enum' && type === 'Bullet')) {
191 description: interpolate(gettext('Change list type to %s'), [label]),
192 execute: execute.changeType
197 toggled: isToggled(params),
198 description: gettext('Remove list'),
199 execute: execute.remove
203 var boundaries = getBoundariesForAList(params.fragment);
204 if(boundaries && boundaries.node1.hasSameContextRoot(boundaries.node2)) {
205 var iterNode = boundaries.node1;
207 if(!iterNode.is({tagName: 'div', klass: 'p'}) && !iterNode.is({tagName: 'header'})) {
210 description: gettext('Invalid element for a list item')
213 if(iterNode.sameNode(boundaries.node2))
215 iterNode = iterNode.next();
220 description: interpolate(gettext('Make %s fragment(s) into list'), [countItems(getBoundariesForAList(params.fragment))]),
230 actions: [toggleListAction('Bullet'), toggleListAction('Enum')]