define([
  'summernote/base/core/agent',
  'summernote/base/core/func',
  'summernote/base/core/list'
], function (agent, func, list) {
  var AirPopover = function (context) {
    var self = this;

    var options = context.options;

    this.events = {
      'summernote.keyup summernote.mouseup summernote.scroll': function () {
        self.update();
      },
      'summernote.change summernote.dialog.shown': function () {
        self.update();
      },
      'summernote.focusout': function (we, e) {
        // [workaround] Firefox doesn't support relatedTarget on focusout
        //  - Ignore hide action on focus out in FF.
        if (agent.isFF) {
          return;
        }

        if (!e.relatedTarget) {
          self.hide();
        }
      }
    };

    this.shouldInitialize = function () {
      return options.airMode &&
        options.popover &&
        options.popover.air &&
        typeof options.popover.air.hide === 'function' &&
        typeof options.popover.air.update === 'function';
    };

    this.initialize = function () {
      this.fontInstalledMap = {};
    };

    this.destroy = function () {
      delete this.fontInstalledMap;
    };

    this.isFontInstalled = function (name) {
      if (!self.fontInstalledMap.hasOwnProperty(name)) {
        self.fontInstalledMap[name] = agent.isFontInstalled(name) ||
          list.contains(options.fontNamesIgnoreCheck, name);
      }

      return self.fontInstalledMap[name];
    };

    this.getAvailablesFont = function () {
      return options.fontNames.filter(self.isFontInstalled);
    };

    this.update = function (force) {
      var styleInfo = context.invoke('editor.currentStyle');
      if (styleInfo.range && (!styleInfo.range.isCollapsed() || force)) {
        var rect = list.last(styleInfo.range.getClientRects());
        var bnd;
        if (rect) {
          bnd = func.rect2bnd(rect);
          options.popover.air.update(styleInfo, bnd);
        } else if (force) {
          options.popover.air.update(styleInfo, null);
        }
      } else {
        this.hide();
      }
    };

    this.hide = function () {
      options.popover.air.hide();
    };
  };

  return AirPopover;
});

@@ -94,16 +94,48 @@
 re/list'
+,%0A  'summernote/base/core/range'
 %0A%5D, func
@@ -157,16 +157,23 @@
 nc, list
+, range
 ) %7B%0A  va
@@ -226,24 +226,107 @@
 lf = this;%0A%0A
+    var $editable = context.layoutInfo.editable;%0A    var editable = $editable%5B0%5D;%0A%0A
     var opti
@@ -861,32 +861,87 @@
 ide();%0A        %7D
+%0A%0A        self.lastRange = range.createFromSelection();
 %0A      %7D%0A    %7D;%0A
@@ -1747,32 +1747,482 @@
 alled);%0A    %7D;%0A%0A
+    this.getLastRange = function () %7B%0A      return self.lastRange;%0A    %7D;%0A%0A    this.insertNode = function (node, rng) %7B%0A      if (!$editable.is(':focus')) %7B%0A        $editable.focus();%0A        rng = rng %7C%7C self.lastRange %7C%7C range.create(editable);%0A        rng.insertNode(node);%0A        self.lastRange = range.createFromNodeAfter(node);%0A        self.lastRange.select();%0A      %7D else %7B%0A        context.invoke('editor.insertNode', node);%0A      %7D%0A    %7D;%0A%0A
     this.update 

Add node insert