Makes sure that the editor body becomes empty when backspace or delete is pressed in empty editors.

For example:
<p><b>|</b></p>

Or:
<h1>|</h1>

Or:
[<h1></h1>]
325306
function emptyEditorWhenDeleting() {
        function serializeRng(rng) {
          var body = dom.create("body");
          var contents = rng.cloneContents();
          body.appendChild(contents);
          return selection.serializer.serialize(body, { format: 'html' });
        }

        function allContentsSelected(rng) {
          if (!rng.setStart) {
            if (rng.item) {
              return false;
            }

            var bodyRng = rng.duplicate();
            bodyRng.moveToElementText(editor.getBody());
            return RangeUtils.compareRanges(rng, bodyRng);
          }

          var selection = serializeRng(rng);

          var allRng = dom.createRng();
          allRng.selectNode(editor.getBody());

          var allSelection = serializeRng(allRng);
          return selection === allSelection;
        }

        editor.on('keydown', function (e) {
          var keyCode = e.keyCode, isCollapsed, body;

          // Empty the editor if it's needed for example backspace at <p><b>|</b></p>
          if (!isDefaultPrevented(e) && (keyCode == DELETE || keyCode == BACKSPACE)) {
            isCollapsed = editor.selection.isCollapsed();
            body = editor.getBody();

            // Selection is collapsed but the editor isn't empty
            if (isCollapsed && !dom.isEmpty(body)) {
              return;
            }

            // Selection isn't collapsed but not all the contents is selected
            if (!isCollapsed && !allContentsSelected(editor.selection.getRng())) {
              return;
            }

            // Manually empty the editor
            e.preventDefault();
            editor.setContent('');

            if (body.firstChild && dom.isBlock(body.firstChild)) {
              editor.selection.setCursorLocation(body.firstChild, 0);
            } else {
              editor.selection.setCursorLocation(body, 0);
            }

            editor.nodeChanged();
          }
        });
      }
1282685
private void cleanContentLeadingSpaces()
    {
        if (getContent().length() > 0) {
            if (fPreviousInlineText.length() == 0
                || fPreviousInlineText
                .charAt(fPreviousInlineText.length() - 1) == ' ')
            {
                trimLeadingWhiteSpaces();
            }
        }
    }
280233
private State skipCommaSpaces(State state) throws IOException {
        wsp1: for (;;) {
            switch (state.current) {
                default:
                    break wsp1;
                case 0x20:
                case 0x9:
                case 0xD:
                case 0xA:
            }
            state.current = state.reader.read();
            state = appendToContext(state);
        }
        if (state.current == ',') {
            wsp2: for (;;) {
                switch (state.current = state.reader.read()) {
                    default:
                        state = appendToContext(state);
                        break wsp2;
                    case 0x20:
                    case 0x9:
                    case 0xA:
                    case 0xD:
                        state = appendToContext(state);
                }
            }
        }
        return state;
    }
37198
function (elements, id) {
      return function (editor) {
        var i, textBlockElementsMap = editor.schema.getTextBlockElements();

        for (i = 0; i < elements.length; i++) {
          if (elements[i].nodeName === 'TABLE') {
            return null;
          }
        }

        for (i = 0; i < elements.length; i++) {
          if (elements[i].nodeName in textBlockElementsMap) {
            if (editor.dom.isEmpty(elements[i])) {
              return Matcher.result(id, Measure.getSelectionRect(editor));
            }

            return null;
          }
        }

        return null;
      };
    }
434092
def backspace!
      if @col > 0
        left, cursor, right = abbrev_segments
        @abbrev = left.chop! + cursor + right
        @col -= 1
        redraw
      end
    end
787823
function () {
      if (hasTag && !nonSpace && !options.space) {
        while (spaces.length) {
          code.splice(spaces.pop(), 1);
        }
      } else {
        spaces = [];
      }

      hasTag = false;
      nonSpace = false;
    }
1272697
def empty_nil_blank?(str, raize=false)
      result = (str !~ /[^[:space:]]/ || str.nil? || str.empty?)
      raise ShellTastic::CommandException.new("Command is emtpy or nil") if result and raize
      result
    end
1248994
function() {
    if(this._oCellEditor) {
        if(this._oCellEditor.cancel) {
            this._oCellEditor.cancel();
        }
        // Backward compatibility
        else if(this._oCellEditor.isActive) {
            this.resetCellEditor();
            //TODO: preserve values for the event?
            this.fireEvent("editorCancelEvent", {editor:this._oCellEditor});
            YAHOO.log("Cell Editor input canceled", "info", this.toString());
        }

        YAHOO.log("CellEditor input canceled", "info", this.toString());
    }
}
1230268
function getTextificationFilter( editor ) {
		var filter = new CKEDITOR.htmlParser.filter();

		// Elements which creates vertical breaks (have vert margins) - took from HTML5 spec.
		// http://dev.w3.org/html5/markup/Overview.html#toc
		var replaceWithParaIf = { blockquote: 1, dl: 1, fieldset: 1, h1: 1, h2: 1, h3: 1, h4: 1, h5: 1, h6: 1, ol: 1, p: 1, table: 1, ul: 1 },

			// All names except of <br>.
			stripInlineIf = CKEDITOR.tools.extend( { br: 0 }, CKEDITOR.dtd.$inline ),

			// What's finally allowed (cke:br will be removed later).
			allowedIf = { p: 1, br: 1, 'cke:br': 1 },

			knownIf = CKEDITOR.dtd,

			// All names that will be removed (with content).
			removeIf = CKEDITOR.tools.extend( { area: 1, basefont: 1, embed: 1, iframe: 1, map: 1, object: 1, param: 1 }, CKEDITOR.dtd.$nonBodyContent, CKEDITOR.dtd.$cdata );

		var flattenTableCell = function( element ) {
				delete element.name;
				element.add( new CKEDITOR.htmlParser.text( ' ' ) );
			},
			// Squash adjacent headers into one. <h1>A</h1><h2>B</h2> -> <h1>A<br>B</h1><h2></h2>
			// Empty ones will be removed later.
			squashHeader = function( element ) {
				var next = element,
					br, el;

				while ( ( next = next.next ) && next.name && next.name.match( /^h\d$/ ) ) {
					// TODO shitty code - waitin' for htmlParse.element fix.
					br = new CKEDITOR.htmlParser.element( 'cke:br' );
					br.isEmpty = true;
					element.add( br );
					while ( ( el = next.children.shift() ) )
						element.add( el );
				}
			};

		filter.addRules( {
			elements: {
				h1: squashHeader,
				h2: squashHeader,
				h3: squashHeader,
				h4: squashHeader,
				h5: squashHeader,
				h6: squashHeader,

				img: function( element ) {
					var alt = CKEDITOR.tools.trim( element.attributes.alt || '' ),
						txt = ' ';

					// Replace image with its alt if it doesn't look like an url or is empty.
					if ( alt && !alt.match( /(^http|\.(jpe?g|gif|png))/i ) )
						txt = ' [' + alt + '] ';

					return new CKEDITOR.htmlParser.text( txt );
				},

				td: flattenTableCell,
				th: flattenTableCell,

				$: function( element ) {
					var initialName = element.name,
						br;

					// Remove entirely.
					if ( removeIf[ initialName ] )
						return false;

					// Remove all attributes.
					element.attributes = {};

					// Pass brs.
					if ( initialName == 'br' )
						return element;

					// Elements that we want to replace with paragraphs.
					if ( replaceWithParaIf[ initialName ] )
						element.name = 'p';

					// Elements that we want to strip (tags only, without the content).
					else if ( stripInlineIf[ initialName ] )
						delete element.name;

					// Surround other known element with <brs> and strip tags.
					else if ( knownIf[ initialName ] ) {
						// TODO shitty code - waitin' for htmlParse.element fix.
						br = new CKEDITOR.htmlParser.element( 'cke:br' );
						br.isEmpty = true;

						// Replace hrs (maybe sth else too?) with only one br.
						if ( CKEDITOR.dtd.$empty[ initialName ] )
							return br;

						element.add( br, 0 );
						br = br.clone();
						br.isEmpty = true;
						element.add( br );
						delete element.name;
					}

					// Final cleanup - if we can still find some not allowed elements then strip their names.
					if ( !allowedIf[ element.name ] )
						delete element.name;

					return element;
				}
			}
		}, {
			// Apply this filter to every element.
			applyToAll: true
		} );

		return filter;
	}
570519
function isEmpty( node ) {
		return node.type == CKEDITOR.NODE_TEXT &&
			!CKEDITOR.tools.trim( node.value ) ||
			node.type == CKEDITOR.NODE_ELEMENT &&
			node.attributes[ 'data-cke-bookmark' ];
	}
857316
def handle_backspace(converted_string, raw_sequence, im_rules=None):
    
    # I can't find a simple explanation for this, so
    # I hope this example can help clarify it:
    #
    # handle_backspace(thương, thuwongw) -> thuwonw
    # handle_backspace(thươn, thuwonw) -> thuwow
    # handle_backspace(thươ, thuwow) -> thuw
    # handle_backspace(thươ, thuw) -> th
    #
    # The algorithm for handle_backspace was contributed by @hainp.

    if im_rules == None:
        im_rules = get_telex_definition()

    deleted_char = converted_string[-1]

    _accent = accent.get_accent_char(deleted_char)
    _mark = mark.get_mark_char(deleted_char)

    if _mark or _accent:
        # Find a sequence of IM keys at the end of
        # raw_sequence

        ime_keys_at_end = ""
        len_raw_sequence = len(raw_sequence)
        i = len_raw_sequence - 1

        while i >= 0:
            if raw_sequence[i] not in im_rules and \
                    raw_sequence[i] not in "aeiouyd":
                i += 1
                break
            else:
                ime_keys_at_end = raw_sequence[i] + ime_keys_at_end
            i -= 1

        # Try to find a subsequence from that sequence
        # that can be converted to the deleted_char
        k = 0
        while k < len_raw_sequence:
            if process_sequence(raw_sequence[i + k:], im_rules) == deleted_char:
                # Delete that subsequence
                raw_sequence = raw_sequence[:i + k]
                break
            k += 1
    else:
        index = raw_sequence.rfind(deleted_char)
        raw_sequence = raw_sequence[:index] + raw_sequence[(index + 1):]

    return raw_sequence
1292951
protected void clearEditor() {

        removeEditOverlays();
        CmsUndoRedoHandler.getInstance().clear();
        m_validationHandler.clear();
        m_entity = null;
        m_entityId = null;
        m_tabInfos = null;
        m_rootHandler = null;
        m_formPanel = null;
        m_formTabs = null;
    }
986149
function activateEditing( editor )
	{
		var win = editor.window,
			doc = editor.document,
			body = editor.document.getBody(),
			bodyFirstChild = body.getFirst(),
			bodyChildsNum = body.getChildren().count();

		if ( !bodyChildsNum
			|| bodyChildsNum == 1
				&& bodyFirstChild.type == CKEDITOR.NODE_ELEMENT
				&& bodyFirstChild.hasAttribute( '_moz_editor_bogus_node' ) )
		{
			restoreDirty( editor );

			// Memorize scroll position to restore it later (#4472).
			var hostDocument = editor.element.getDocument();
			var hostDocumentElement = hostDocument.getDocumentElement();
			var scrollTop = hostDocumentElement.$.scrollTop;
			var scrollLeft = hostDocumentElement.$.scrollLeft;

			// Simulating keyboard character input by dispatching a keydown of white-space text.
			var keyEventSimulate = doc.$.createEvent( "KeyEvents" );
			keyEventSimulate.initKeyEvent( 'keypress', true, true, win.$, false,
				false, false, false, 0, 32 );
			doc.$.dispatchEvent( keyEventSimulate );

			if ( scrollTop != hostDocumentElement.$.scrollTop || scrollLeft != hostDocumentElement.$.scrollLeft )
				hostDocument.getWindow().$.scrollTo( scrollLeft, scrollTop );

			// Restore the original document status by placing the cursor before a bogus br created (#5021).
			bodyChildsNum && body.getFirst().remove();
			doc.getBody().appendBogus();
			var nativeRange = new CKEDITOR.dom.range( doc );
			nativeRange.setStartAt( body , CKEDITOR.POSITION_AFTER_START );
			nativeRange.select();
		}
	}
609688
private void handleEmptySelects() {
    getLogger().debug("No selectors ready, interrupted: %b",
      Thread.interrupted());

    if (++emptySelects > DOUBLE_CHECK_EMPTY) {
      for (SelectionKey sk : selector.keys()) {
        getLogger().debug("%s has %s, interested in %s", sk, sk.readyOps(),
          sk.interestOps());
        if (sk.readyOps() != 0) {
          getLogger().debug("%s has a ready op, handling IO", sk);
          handleIO(sk);
        } else {
          lostConnection((MemcachedNode) sk.attachment());
        }
      }
      assert emptySelects < EXCESSIVE_EMPTY : "Too many empty selects";
    }
  }
864912
def empty_content?(element)
        text = +""
        child_nodes = element.child_nodes
        (0...child_nodes.length).each do |i|
          item = child_nodes.item(i)
          if item.node_type == Node.TEXT_NODE
            text << item.get_data.strip
          end
        end
        text.strip.length == 0
      end
1337610
@Override
    public void doExecute() {
        if (!getEditor().isReadOnly()) {
            deleted = getEditor().delete().charAt(0);
            getEditor().put(replace);
            getEditor().moveLeft(replace.length());
        }
    }
869569
function onBackspace(
    event: *,
    change: Change,
    editor: *,
    opts: Options
): void | any {
    const { value } = change;
    const { startOffset, selection } = value;

    // Only unwrap...
    // ... with a collapsed selection
    if (selection.isExpanded) {
        return undefined;
    }

    // ... when at the beginning of nodes
    if (startOffset > 0) {
        return undefined;
    }
    // ... in a list
    const currentItem = getCurrentItem(opts, value);
    if (!currentItem) {
        return undefined;
    }
    // ... more precisely at the beginning of the current item
    if (!selection.isAtStartOf(currentItem)) {
        return undefined;
    }

    event.preventDefault();
    return unwrapList(opts, change);
}