]> scripts.mit.edu Git - autoinstalls/wordpress.git/blob - wp-includes/js/tinymce/plugins/lists/plugin.js
WordPress 4.3.1
[autoinstalls/wordpress.git] / wp-includes / js / tinymce / plugins / lists / plugin.js
1 /**
2  * plugin.js
3  *
4  * Released under LGPL License.
5  * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
6  *
7  * License: http://www.tinymce.com/license
8  * Contributing: http://www.tinymce.com/contributing
9  */
10
11 /*global tinymce:true */
12 /*eslint consistent-this:0 */
13
14 tinymce.PluginManager.add('lists', function(editor) {
15         var self = this;
16
17         function isListNode(node) {
18                 return node && (/^(OL|UL|DL)$/).test(node.nodeName);
19         }
20
21         function isFirstChild(node) {
22                 return node.parentNode.firstChild == node;
23         }
24
25         function isLastChild(node) {
26                 return node.parentNode.lastChild == node;
27         }
28
29         function isTextBlock(node) {
30                 return node && !!editor.schema.getTextBlockElements()[node.nodeName];
31         }
32
33         editor.on('init', function() {
34                 var dom = editor.dom, selection = editor.selection;
35
36                 /**
37                  * Returns a range bookmark. This will convert indexed bookmarks into temporary span elements with
38                  * index 0 so that they can be restored properly after the DOM has been modified. Text bookmarks will not have spans
39                  * added to them since they can be restored after a dom operation.
40                  *
41                  * So this: <p><b>|</b><b>|</b></p>
42                  * becomes: <p><b><span data-mce-type="bookmark">|</span></b><b data-mce-type="bookmark">|</span></b></p>
43                  *
44                  * @param  {DOMRange} rng DOM Range to get bookmark on.
45                  * @return {Object} Bookmark object.
46                  */
47                 function createBookmark(rng) {
48                         var bookmark = {};
49
50                         function setupEndPoint(start) {
51                                 var offsetNode, container, offset;
52
53                                 container = rng[start ? 'startContainer' : 'endContainer'];
54                                 offset = rng[start ? 'startOffset' : 'endOffset'];
55
56                                 if (container.nodeType == 1) {
57                                         offsetNode = dom.create('span', {'data-mce-type': 'bookmark'});
58
59                                         if (container.hasChildNodes()) {
60                                                 offset = Math.min(offset, container.childNodes.length - 1);
61
62                                                 if (start) {
63                                                         container.insertBefore(offsetNode, container.childNodes[offset]);
64                                                 } else {
65                                                         dom.insertAfter(offsetNode, container.childNodes[offset]);
66                                                 }
67                                         } else {
68                                                 container.appendChild(offsetNode);
69                                         }
70
71                                         container = offsetNode;
72                                         offset = 0;
73                                 }
74
75                                 bookmark[start ? 'startContainer' : 'endContainer'] = container;
76                                 bookmark[start ? 'startOffset' : 'endOffset'] = offset;
77                         }
78
79                         setupEndPoint(true);
80
81                         if (!rng.collapsed) {
82                                 setupEndPoint();
83                         }
84
85                         return bookmark;
86                 }
87
88                 /**
89                  * Moves the selection to the current bookmark and removes any selection container wrappers.
90                  *
91                  * @param {Object} bookmark Bookmark object to move selection to.
92                  */
93                 function moveToBookmark(bookmark) {
94                         function restoreEndPoint(start) {
95                                 var container, offset, node;
96
97                                 function nodeIndex(container) {
98                                         var node = container.parentNode.firstChild, idx = 0;
99
100                                         while (node) {
101                                                 if (node == container) {
102                                                         return idx;
103                                                 }
104
105                                                 // Skip data-mce-type=bookmark nodes
106                                                 if (node.nodeType != 1 || node.getAttribute('data-mce-type') != 'bookmark') {
107                                                         idx++;
108                                                 }
109
110                                                 node = node.nextSibling;
111                                         }
112
113                                         return -1;
114                                 }
115
116                                 container = node = bookmark[start ? 'startContainer' : 'endContainer'];
117                                 offset = bookmark[start ? 'startOffset' : 'endOffset'];
118
119                                 if (!container) {
120                                         return;
121                                 }
122
123                                 if (container.nodeType == 1) {
124                                         offset = nodeIndex(container);
125                                         container = container.parentNode;
126                                         dom.remove(node);
127                                 }
128
129                                 bookmark[start ? 'startContainer' : 'endContainer'] = container;
130                                 bookmark[start ? 'startOffset' : 'endOffset'] = offset;
131                         }
132
133                         restoreEndPoint(true);
134                         restoreEndPoint();
135
136                         var rng = dom.createRng();
137
138                         rng.setStart(bookmark.startContainer, bookmark.startOffset);
139
140                         if (bookmark.endContainer) {
141                                 rng.setEnd(bookmark.endContainer, bookmark.endOffset);
142                         }
143
144                         selection.setRng(rng);
145                 }
146
147                 function createNewTextBlock(contentNode, blockName) {
148                         var node, textBlock, fragment = dom.createFragment(), hasContentNode;
149                         var blockElements = editor.schema.getBlockElements();
150
151                         if (editor.settings.forced_root_block) {
152                                 blockName = blockName || editor.settings.forced_root_block;
153                         }
154
155                         if (blockName) {
156                                 textBlock = dom.create(blockName);
157
158                                 if (textBlock.tagName === editor.settings.forced_root_block) {
159                                         dom.setAttribs(textBlock, editor.settings.forced_root_block_attrs);
160                                 }
161
162                                 fragment.appendChild(textBlock);
163                         }
164
165                         if (contentNode) {
166                                 while ((node = contentNode.firstChild)) {
167                                         var nodeName = node.nodeName;
168
169                                         if (!hasContentNode && (nodeName != 'SPAN' || node.getAttribute('data-mce-type') != 'bookmark')) {
170                                                 hasContentNode = true;
171                                         }
172
173                                         if (blockElements[nodeName]) {
174                                                 fragment.appendChild(node);
175                                                 textBlock = null;
176                                         } else {
177                                                 if (blockName) {
178                                                         if (!textBlock) {
179                                                                 textBlock = dom.create(blockName);
180                                                                 fragment.appendChild(textBlock);
181                                                         }
182
183                                                         textBlock.appendChild(node);
184                                                 } else {
185                                                         fragment.appendChild(node);
186                                                 }
187                                         }
188                                 }
189                         }
190
191                         if (!editor.settings.forced_root_block) {
192                                 fragment.appendChild(dom.create('br'));
193                         } else {
194                                 // BR is needed in empty blocks on non IE browsers
195                                 if (!hasContentNode && (!tinymce.Env.ie || tinymce.Env.ie > 10)) {
196                                         textBlock.appendChild(dom.create('br', {'data-mce-bogus': '1'}));
197                                 }
198                         }
199
200                         return fragment;
201                 }
202
203                 function getSelectedListItems() {
204                         return tinymce.grep(selection.getSelectedBlocks(), function(block) {
205                                 return /^(LI|DT|DD)$/.test(block.nodeName);
206                         });
207                 }
208
209                 function splitList(ul, li, newBlock) {
210                         var tmpRng, fragment, bookmarks, node;
211
212                         function removeAndKeepBookmarks(targetNode) {
213                                 tinymce.each(bookmarks, function(node) {
214                                         targetNode.parentNode.insertBefore(node, li.parentNode);
215                                 });
216
217                                 dom.remove(targetNode);
218                         }
219
220                         bookmarks = dom.select('span[data-mce-type="bookmark"]', ul);
221                         newBlock = newBlock || createNewTextBlock(li);
222                         tmpRng = dom.createRng();
223                         tmpRng.setStartAfter(li);
224                         tmpRng.setEndAfter(ul);
225                         fragment = tmpRng.extractContents();
226
227                         for (node = fragment.firstChild; node; node = node.firstChild) {
228                                 if (node.nodeName == 'LI' && dom.isEmpty(node)) {
229                                         dom.remove(node);
230                                         break;
231                                 }
232                         }
233
234                         if (!dom.isEmpty(fragment)) {
235                                 dom.insertAfter(fragment, ul);
236                         }
237
238                         dom.insertAfter(newBlock, ul);
239
240                         if (dom.isEmpty(li.parentNode)) {
241                                 removeAndKeepBookmarks(li.parentNode);
242                         }
243
244                         dom.remove(li);
245
246                         if (dom.isEmpty(ul)) {
247                                 dom.remove(ul);
248                         }
249                 }
250
251                 function mergeWithAdjacentLists(listBlock) {
252                         var sibling, node;
253
254                         sibling = listBlock.nextSibling;
255                         if (sibling && isListNode(sibling) && sibling.nodeName == listBlock.nodeName) {
256                                 while ((node = sibling.firstChild)) {
257                                         listBlock.appendChild(node);
258                                 }
259
260                                 dom.remove(sibling);
261                         }
262
263                         sibling = listBlock.previousSibling;
264                         if (sibling && isListNode(sibling) && sibling.nodeName == listBlock.nodeName) {
265                                 while ((node = sibling.firstChild)) {
266                                         listBlock.insertBefore(node, listBlock.firstChild);
267                                 }
268
269                                 dom.remove(sibling);
270                         }
271                 }
272
273                 /**
274                  * Normalizes the all lists in the specified element.
275                  */
276                 function normalizeList(element) {
277                         tinymce.each(tinymce.grep(dom.select('ol,ul', element)), function(ul) {
278                                 var sibling, parentNode = ul.parentNode;
279
280                                 // Move UL/OL to previous LI if it's the only child of a LI
281                                 if (parentNode.nodeName == 'LI' && parentNode.firstChild == ul) {
282                                         sibling = parentNode.previousSibling;
283                                         if (sibling && sibling.nodeName == 'LI') {
284                                                 sibling.appendChild(ul);
285
286                                                 if (dom.isEmpty(parentNode)) {
287                                                         dom.remove(parentNode);
288                                                 }
289                                         }
290                                 }
291
292                                 // Append OL/UL to previous LI if it's in a parent OL/UL i.e. old HTML4
293                                 if (isListNode(parentNode)) {
294                                         sibling = parentNode.previousSibling;
295                                         if (sibling && sibling.nodeName == 'LI') {
296                                                 sibling.appendChild(ul);
297                                         }
298                                 }
299                         });
300                 }
301
302                 function outdent(li) {
303                         var ul = li.parentNode, ulParent = ul.parentNode, newBlock;
304
305                         function removeEmptyLi(li) {
306                                 if (dom.isEmpty(li)) {
307                                         dom.remove(li);
308                                 }
309                         }
310
311                         if (li.nodeName == 'DD') {
312                                 dom.rename(li, 'DT');
313                                 return true;
314                         }
315
316                         if (isFirstChild(li) && isLastChild(li)) {
317                                 if (ulParent.nodeName == "LI") {
318                                         dom.insertAfter(li, ulParent);
319                                         removeEmptyLi(ulParent);
320                                         dom.remove(ul);
321                                 } else if (isListNode(ulParent)) {
322                                         dom.remove(ul, true);
323                                 } else {
324                                         ulParent.insertBefore(createNewTextBlock(li), ul);
325                                         dom.remove(ul);
326                                 }
327
328                                 return true;
329                         } else if (isFirstChild(li)) {
330                                 if (ulParent.nodeName == "LI") {
331                                         dom.insertAfter(li, ulParent);
332                                         li.appendChild(ul);
333                                         removeEmptyLi(ulParent);
334                                 } else if (isListNode(ulParent)) {
335                                         ulParent.insertBefore(li, ul);
336                                 } else {
337                                         ulParent.insertBefore(createNewTextBlock(li), ul);
338                                         dom.remove(li);
339                                 }
340
341                                 return true;
342                         } else if (isLastChild(li)) {
343                                 if (ulParent.nodeName == "LI") {
344                                         dom.insertAfter(li, ulParent);
345                                 } else if (isListNode(ulParent)) {
346                                         dom.insertAfter(li, ul);
347                                 } else {
348                                         dom.insertAfter(createNewTextBlock(li), ul);
349                                         dom.remove(li);
350                                 }
351
352                                 return true;
353                         }
354
355                         if (ulParent.nodeName == 'LI') {
356                                 ul = ulParent;
357                                 newBlock = createNewTextBlock(li, 'LI');
358                         } else if (isListNode(ulParent)) {
359                                 newBlock = createNewTextBlock(li, 'LI');
360                         } else {
361                                 newBlock = createNewTextBlock(li);
362                         }
363
364                         splitList(ul, li, newBlock);
365                         normalizeList(ul.parentNode);
366
367                         return true;
368                 }
369
370                 function indent(li) {
371                         var sibling, newList;
372
373                         function mergeLists(from, to) {
374                                 var node;
375
376                                 if (isListNode(from)) {
377                                         while ((node = li.lastChild.firstChild)) {
378                                                 to.appendChild(node);
379                                         }
380
381                                         dom.remove(from);
382                                 }
383                         }
384
385                         if (li.nodeName == 'DT') {
386                                 dom.rename(li, 'DD');
387                                 return true;
388                         }
389
390                         sibling = li.previousSibling;
391
392                         if (sibling && isListNode(sibling)) {
393                                 sibling.appendChild(li);
394                                 return true;
395                         }
396
397                         if (sibling && sibling.nodeName == 'LI' && isListNode(sibling.lastChild)) {
398                                 sibling.lastChild.appendChild(li);
399                                 mergeLists(li.lastChild, sibling.lastChild);
400                                 return true;
401                         }
402
403                         sibling = li.nextSibling;
404
405                         if (sibling && isListNode(sibling)) {
406                                 sibling.insertBefore(li, sibling.firstChild);
407                                 return true;
408                         }
409
410                         if (sibling && sibling.nodeName == 'LI' && isListNode(li.lastChild)) {
411                                 return false;
412                         }
413
414                         sibling = li.previousSibling;
415                         if (sibling && sibling.nodeName == 'LI') {
416                                 newList = dom.create(li.parentNode.nodeName);
417                                 sibling.appendChild(newList);
418                                 newList.appendChild(li);
419                                 mergeLists(li.lastChild, newList);
420                                 return true;
421                         }
422
423                         return false;
424                 }
425
426                 function indentSelection() {
427                         var listElements = getSelectedListItems();
428
429                         if (listElements.length) {
430                                 var bookmark = createBookmark(selection.getRng(true));
431
432                                 for (var i = 0; i < listElements.length; i++) {
433                                         if (!indent(listElements[i]) && i === 0) {
434                                                 break;
435                                         }
436                                 }
437
438                                 moveToBookmark(bookmark);
439                                 editor.nodeChanged();
440
441                                 return true;
442                         }
443                 }
444
445                 function outdentSelection() {
446                         var listElements = getSelectedListItems();
447
448                         if (listElements.length) {
449                                 var bookmark = createBookmark(selection.getRng(true));
450                                 var i, y, root = editor.getBody();
451
452                                 i = listElements.length;
453                                 while (i--) {
454                                         var node = listElements[i].parentNode;
455
456                                         while (node && node != root) {
457                                                 y = listElements.length;
458                                                 while (y--) {
459                                                         if (listElements[y] === node) {
460                                                                 listElements.splice(i, 1);
461                                                                 break;
462                                                         }
463                                                 }
464
465                                                 node = node.parentNode;
466                                         }
467                                 }
468
469                                 for (i = 0; i < listElements.length; i++) {
470                                         if (!outdent(listElements[i]) && i === 0) {
471                                                 break;
472                                         }
473                                 }
474
475                                 moveToBookmark(bookmark);
476                                 editor.nodeChanged();
477
478                                 return true;
479                         }
480                 }
481
482                 function applyList(listName) {
483                         var rng = selection.getRng(true), bookmark = createBookmark(rng), listItemName = 'LI';
484
485                         listName = listName.toUpperCase();
486
487                         if (listName == 'DL') {
488                                 listItemName = 'DT';
489                         }
490
491                         function getSelectedTextBlocks() {
492                                 var textBlocks = [], root = editor.getBody();
493
494                                 function getEndPointNode(start) {
495                                         var container, offset;
496
497                                         container = rng[start ? 'startContainer' : 'endContainer'];
498                                         offset = rng[start ? 'startOffset' : 'endOffset'];
499
500                                         // Resolve node index
501                                         if (container.nodeType == 1) {
502                                                 container = container.childNodes[Math.min(offset, container.childNodes.length - 1)] || container;
503                                         }
504
505                                         while (container.parentNode != root) {
506                                                 if (isTextBlock(container)) {
507                                                         return container;
508                                                 }
509
510                                                 if (/^(TD|TH)$/.test(container.parentNode.nodeName)) {
511                                                         return container;
512                                                 }
513
514                                                 container = container.parentNode;
515                                         }
516
517                                         return container;
518                                 }
519
520                                 var startNode = getEndPointNode(true);
521                                 var endNode = getEndPointNode();
522                                 var block, siblings = [];
523
524                                 for (var node = startNode; node; node = node.nextSibling) {
525                                         siblings.push(node);
526
527                                         if (node == endNode) {
528                                                 break;
529                                         }
530                                 }
531
532                                 tinymce.each(siblings, function(node) {
533                                         if (isTextBlock(node)) {
534                                                 textBlocks.push(node);
535                                                 block = null;
536                                                 return;
537                                         }
538
539                                         if (dom.isBlock(node) || node.nodeName == 'BR') {
540                                                 if (node.nodeName == 'BR') {
541                                                         dom.remove(node);
542                                                 }
543
544                                                 block = null;
545                                                 return;
546                                         }
547
548                                         var nextSibling = node.nextSibling;
549                                         if (tinymce.dom.BookmarkManager.isBookmarkNode(node)) {
550                                                 if (isTextBlock(nextSibling) || (!nextSibling && node.parentNode == root)) {
551                                                         block = null;
552                                                         return;
553                                                 }
554                                         }
555
556                                         if (!block) {
557                                                 block = dom.create('p');
558                                                 node.parentNode.insertBefore(block, node);
559                                                 textBlocks.push(block);
560                                         }
561
562                                         block.appendChild(node);
563                                 });
564
565                                 return textBlocks;
566                         }
567
568                         tinymce.each(getSelectedTextBlocks(), function(block) {
569                                 var listBlock, sibling;
570
571                                 sibling = block.previousSibling;
572                                 if (sibling && isListNode(sibling) && sibling.nodeName == listName) {
573                                         listBlock = sibling;
574                                         block = dom.rename(block, listItemName);
575                                         sibling.appendChild(block);
576                                 } else {
577                                         listBlock = dom.create(listName);
578                                         block.parentNode.insertBefore(listBlock, block);
579                                         listBlock.appendChild(block);
580                                         block = dom.rename(block, listItemName);
581                                 }
582
583                                 mergeWithAdjacentLists(listBlock);
584                         });
585
586                         moveToBookmark(bookmark);
587                 }
588
589                 function removeList() {
590                         var bookmark = createBookmark(selection.getRng(true)), root = editor.getBody();
591
592                         tinymce.each(getSelectedListItems(), function(li) {
593                                 var node, rootList;
594
595                                 if (dom.isEmpty(li)) {
596                                         outdent(li);
597                                         return;
598                                 }
599
600                                 for (node = li; node && node != root; node = node.parentNode) {
601                                         if (isListNode(node)) {
602                                                 rootList = node;
603                                         }
604                                 }
605
606                                 splitList(rootList, li);
607                         });
608
609                         moveToBookmark(bookmark);
610                 }
611
612                 function toggleList(listName) {
613                         var parentList = dom.getParent(selection.getStart(), 'OL,UL,DL');
614
615                         if (parentList) {
616                                 if (parentList.nodeName == listName) {
617                                         removeList(listName);
618                                 } else {
619                                         var bookmark = createBookmark(selection.getRng(true));
620                                         mergeWithAdjacentLists(dom.rename(parentList, listName));
621                                         moveToBookmark(bookmark);
622                                 }
623                         } else {
624                                 applyList(listName);
625                         }
626                 }
627
628                 function queryListCommandState(listName) {
629                         return function() {
630                                 var parentList = dom.getParent(editor.selection.getStart(), 'UL,OL,DL');
631
632                                 return parentList && parentList.nodeName == listName;
633                         };
634                 }
635
636                 self.backspaceDelete = function(isForward) {
637                         function findNextCaretContainer(rng, isForward) {
638                                 var node = rng.startContainer, offset = rng.startOffset;
639                                 var nonEmptyBlocks, walker;
640
641                                 if (node.nodeType == 3 && (isForward ? offset < node.data.length : offset > 0)) {
642                                         return node;
643                                 }
644
645                                 nonEmptyBlocks = editor.schema.getNonEmptyElements();
646                                 walker = new tinymce.dom.TreeWalker(rng.startContainer);
647
648                                 while ((node = walker[isForward ? 'next' : 'prev']())) {
649                                         if (node.nodeName == 'LI' && !node.hasChildNodes()) {
650                                                 return node;
651                                         }
652
653                                         if (nonEmptyBlocks[node.nodeName]) {
654                                                 return node;
655                                         }
656
657                                         if (node.nodeType == 3 && node.data.length > 0) {
658                                                 return node;
659                                         }
660                                 }
661                         }
662
663                         function mergeLiElements(fromElm, toElm) {
664                                 var node, listNode, ul = fromElm.parentNode;
665
666                                 if (isListNode(toElm.lastChild)) {
667                                         listNode = toElm.lastChild;
668                                 }
669
670                                 node = toElm.lastChild;
671                                 if (node && node.nodeName == 'BR' && fromElm.hasChildNodes()) {
672                                         dom.remove(node);
673                                 }
674
675                                 if (dom.isEmpty(toElm)) {
676                                         dom.$(toElm).empty();
677                                 }
678
679                                 if (!dom.isEmpty(fromElm)) {
680                                         while ((node = fromElm.firstChild)) {
681                                                 toElm.appendChild(node);
682                                         }
683                                 }
684
685                                 if (listNode) {
686                                         toElm.appendChild(listNode);
687                                 }
688
689                                 dom.remove(fromElm);
690
691                                 if (dom.isEmpty(ul)) {
692                                         dom.remove(ul);
693                                 }
694                         }
695
696                         if (selection.isCollapsed()) {
697                                 var li = dom.getParent(selection.getStart(), 'LI');
698
699                                 if (li) {
700                                         var rng = selection.getRng(true);
701                                         var otherLi = dom.getParent(findNextCaretContainer(rng, isForward), 'LI');
702
703                                         if (otherLi && otherLi != li) {
704                                                 var bookmark = createBookmark(rng);
705
706                                                 if (isForward) {
707                                                         mergeLiElements(otherLi, li);
708                                                 } else {
709                                                         mergeLiElements(li, otherLi);
710                                                 }
711
712                                                 moveToBookmark(bookmark);
713
714                                                 return true;
715                                         } else if (!otherLi) {
716                                                 if (!isForward && removeList(li.parentNode.nodeName)) {
717                                                         return true;
718                                                 }
719                                         }
720                                 }
721                         }
722                 };
723
724                 editor.on('BeforeExecCommand', function(e) {
725                         var cmd = e.command.toLowerCase(), isHandled;
726
727                         if (cmd == "indent") {
728                                 if (indentSelection()) {
729                                         isHandled = true;
730                                 }
731                         } else if (cmd == "outdent") {
732                                 if (outdentSelection()) {
733                                         isHandled = true;
734                                 }
735                         }
736
737                         if (isHandled) {
738                                 editor.fire('ExecCommand', {command: e.command});
739                                 e.preventDefault();
740                                 return true;
741                         }
742                 });
743
744                 editor.addCommand('InsertUnorderedList', function() {
745                         toggleList('UL');
746                 });
747
748                 editor.addCommand('InsertOrderedList', function() {
749                         toggleList('OL');
750                 });
751
752                 editor.addCommand('InsertDefinitionList', function() {
753                         toggleList('DL');
754                 });
755
756                 editor.addQueryStateHandler('InsertUnorderedList', queryListCommandState('UL'));
757                 editor.addQueryStateHandler('InsertOrderedList', queryListCommandState('OL'));
758                 editor.addQueryStateHandler('InsertDefinitionList', queryListCommandState('DL'));
759
760                 editor.on('keydown', function(e) {
761                         // Check for tab but not ctrl/cmd+tab since it switches browser tabs
762                         if (e.keyCode != 9 || tinymce.util.VK.metaKeyPressed(e)) {
763                                 return;
764                         }
765
766                         if (editor.dom.getParent(editor.selection.getStart(), 'LI,DT,DD')) {
767                                 e.preventDefault();
768
769                                 if (e.shiftKey) {
770                                         outdentSelection();
771                                 } else {
772                                         indentSelection();
773                                 }
774                         }
775                 });
776         });
777
778         editor.addButton('indent', {
779                 icon: 'indent',
780                 title: 'Increase indent',
781                 cmd: 'Indent',
782                 onPostRender: function() {
783                         var ctrl = this;
784
785                         editor.on('nodechange', function() {
786                                 var blocks = editor.selection.getSelectedBlocks();
787                                 var disable = false;
788
789                                 for (var i = 0, l = blocks.length; !disable && i < l; i++) {
790                                         var tag = blocks[i].nodeName;
791
792                                         disable = (tag == 'LI' && isFirstChild(blocks[i]) || tag == 'UL' || tag == 'OL' || tag == 'DD');
793                                 }
794
795                                 ctrl.disabled(disable);
796                         });
797                 }
798         });
799
800         editor.on('keydown', function(e) {
801                 if (e.keyCode == tinymce.util.VK.BACKSPACE) {
802                         if (self.backspaceDelete()) {
803                                 e.preventDefault();
804                         }
805                 } else if (e.keyCode == tinymce.util.VK.DELETE) {
806                         if (self.backspaceDelete(true)) {
807                                 e.preventDefault();
808                         }
809                 }
810         });
811 });