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 current.document.transaction(function() {
96 var p = list.after({tagName: 'div', attrs: {'class': 'p'}});
97 p.append({text: current.getText()});
99 if(list.contents().length === 0) {
102 return current.document.createFragment(current.document.NodeFragment, {node: p});
105 description: action.getState().description,
106 fragment: params.fragment
113 var toSearch = current.nodeType === Node.ELEMENT_NODE ? [current] : [];
114 toSearch = toSearch.concat(current.parents());
115 toSearch.some(function(node) {
116 if(node.is('list')) {
117 node.document.transaction(function() {
118 var firstItem = node.object.extractListItems(),
120 if(params.fragment.isValid()) {
121 toret = params.fragment;
123 toret = node.document.createFragment(node.document.NodeFragment, {node: firstItem});
128 description: action.getState().description,
129 fragment: params.fragment
134 return true; // break
138 changeType: function(callback, params) {
139 var node = params.fragment.node,
141 node.document.transaction(function() {
142 var list = node.getParent('list');
143 list.setClass(type === 'Bullet' ? 'list' : 'list.enum');
144 if(params.fragment.isValid()) {
145 return params.fragment;
147 return node.document.createFragment(node.document.NodeFragment, {node: list.contents()[0]});
151 description: action.getState().description,
152 fragment: params.fragment
159 var isToggled = function(params) {
160 if(params.fragment && params.fragment.node && params.fragment.node.isInside('list')) {
161 var list = params.fragment.node.getParent('list');
162 return list.getClass() === (type === 'Bullet' ? 'list' : 'list.enum');
167 var label = type === 'Bullet' ? gettext('bull. list') : gettext('num. list');
170 name: 'toggle' + type + 'List',
171 context: ['fragment'],
173 fragment: {type: 'context', name: 'fragment'}
178 getState: function(params) {
179 if(!params.fragment || !params.fragment.isValid()) {
183 if(params.fragment instanceof params.fragment.CaretFragment && params.fragment.node.isInside('list')) {
184 var list = params.fragment.node.getParent('list');
185 if((list.getClass() === 'list' && type === 'Enum') || (list.getClass() === 'list.enum' && type === 'Bullet')) {
188 description: interpolate(gettext('Change list type to %s'), [label]),
189 execute: execute.changeType
194 toggled: isToggled(params),
195 description: gettext('Remove list'),
196 execute: execute.remove
200 var boundaries = getBoundariesForAList(params.fragment);
201 if(boundaries && boundaries.node1.hasSameContextRoot(boundaries.node2)) {
202 var iterNode = boundaries.node1;
204 if(!iterNode.is({tagName: 'div', klass: 'p'}) && !iterNode.is({tagName: 'header'})) {
207 description: gettext('Invalid element for a list item')
210 if(iterNode.sameNode(boundaries.node2))
212 iterNode = iterNode.next();
217 description: interpolate(gettext('Make %s fragment(s) into list'), [countItems(getBoundariesForAList(params.fragment))]),
227 actions: [toggleListAction('Bullet'), toggleListAction('Enum')]