Skip to content

Commit

Permalink
Merge pull request #1352 from summernote/recover-hint-popover
Browse files Browse the repository at this point in the history
Recover hint popover
  • Loading branch information
hackerwins committed Oct 2, 2015
2 parents 01f78c8 + f528607 commit 2579963
Show file tree
Hide file tree
Showing 10 changed files with 492 additions and 413 deletions.
2 changes: 1 addition & 1 deletion dist/summernote.css

Large diffs are not rendered by default.

212 changes: 211 additions & 1 deletion dist/summernote.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* Copyright 2013-2015 Alan Hong. and other contributors
* summernote may be freely distributed under the MIT license./
*
* Date: 2015-10-02T03:01Z
* Date: 2015-10-02T08:24Z
*/
(function (factory) {
/* global define */
Expand Down Expand Up @@ -5803,6 +5803,215 @@
};
};

var HintPopover = function (summernote) {
var self = this;
var ui = $.summernote.ui;

var $note = summernote.layoutInfo.note;
var hint = summernote.options.hint || [];
var hints = (hint instanceof Array) ? hint : [hint];

this.events = {
'summernote.keyup': function (we, e) {
self.handleKeyup(e);
},
'summernote.keydown' : function (we, e) {
self.handleKeydown(e);
}
};

this.initialize = function () {
if (!hints.length) {
return;
}

this.lastWordRange = null;
this.$popover = ui.popover({
className: 'note-hint-popover'
}).render().appendTo('body');

this.$content = this.$popover.find('.popover-content');

dom.attachEvents($note, this.events);

this.$content.on('click', '.note-hint-item', function () {
self.$content.find('.active').removeClass('active');
$(this).addClass('active');
self.replace();
});
};

this.destroy = function () {
if (!hints.length) {
return;
}

this.$popover.remove();
dom.detachEvents($note, this.events);
};

this.selectItem = function ($item) {
this.$content.find('.active').removeClass('active');
$item.addClass('active');

this.$content[0].scrollTop = $item[0].offsetTop - (this.$content.innerHeight() / 2);
};

this.moveDown = function () {
var $current = this.$content.find('.note-hint-item.active');
var $next = $current.next();

if ($next.length) {
this.selectItem($next);
} else {
var $nextGroup = $current.parent().next();

if (!$nextGroup.length) {
$nextGroup = this.$content.find('.note-hint-group').first();
}

this.selectItem($nextGroup.find('.note-hint-item').first());
}
};

this.moveUp = function () {
var $current = this.$content.find('.note-hint-item.active');
var $prev = $current.prev();

if ($prev.length) {
this.selectItem($prev);
} else {
var $prevGroup = $current.parent().prev();

if (!$prevGroup.length) {
$prevGroup = this.$content.find('.note-hint-group').last();
}

this.selectItem($prevGroup.find('.note-hint-item').last());
}
};

this.replace = function () {
var $item = this.$content.find('.note-hint-item.active');
var node = this.nodeFromItem($item);
this.lastWordRange.insertNode(node);
range.createFromNode(node).collapse().select();

this.lastWordRange = null;
this.hide();
summernote.invoke('editor.focus');
};

this.nodeFromItem = function ($item) {
var hint = hints[$item.data('index')];
var item = $item.data('item');
var node = hint.content ? hint.content(item) : item;
if (typeof node === 'string') {
node = dom.createText(node);
}
return node;
};

this.createItemTemplates = function (hintIdx, items) {
var hint = hints[hintIdx];
return items.map(function (item, idx) {
var $item = $('<div class="note-hint-item"/>');
$item.append(hint.template ? hint.template(item) : item + '');
$item.data({
'index': hintIdx,
'item': item
});

if (hintIdx === 0 && idx === 0) {
$item.addClass('active');
}
return $item;
});
};

this.handleKeydown = function (e) {
if (!this.$popover.is(':visible')) {
return;
}

if (e.keyCode === key.code.ENTER) {
e.preventDefault();
this.replace();
} else if (e.keyCode === key.code.UP) {
e.preventDefault();
this.moveUp();
} else if (e.keyCode === key.code.DOWN) {
e.preventDefault();
this.moveDown();
}
};

this.searchKeyword = function (index, keyword, callback) {
var hint = hints[index];
if (hint && hint.match.test(keyword) && hint.search) {
var matches = hint.match.exec(keyword);
hint.search(matches[1], callback);
} else {
callback();
}
};

this.createGroup = function (idx, keyword) {
var $group = $('<div class="note-hint-group note-hint-group-' + idx + '"/>');
this.searchKeyword(idx, keyword, function (items) {
items = items || [];
if (items.length) {
$group.html(self.createItemTemplates(idx, items));
self.show();
}
});

return $group;
};

this.handleKeyup = function (e) {
if (list.contains([key.code.ENTER, key.code.UP, key.code.DOWN], e.keyCode)) {
if (e.keyCode === key.code.ENTER) {
if (this.$popover.is(':visible')) {
return false;
}
}
} else {
var wordRange = summernote.invoke('editor.createRange').getWordRange();
var keyword = wordRange.toString();
if (hints.length && keyword) {
this.$content.empty().data('count', 0);

var bnd = func.rect2bnd(list.last(wordRange.getClientRects()));
if (bnd) {
this.$popover.css({
left: bnd.left,
top: bnd.top + bnd.height
}).hide();

this.lastWordRange = wordRange;

hints.forEach(function (hint, idx) {
if (hint.match.test(keyword)) {
self.createGroup(idx, keyword).appendTo(self.$content);
}
});
}
} else {
this.hide();
}
}
};

this.show = function () {
this.$popover.show();
};

this.hide = function () {
this.$popover.hide();
};
};

var SpecialCharDialog = function (summernote) {
var self = this;
var ui = $.summernote.ui;
Expand Down Expand Up @@ -6354,6 +6563,7 @@
'imagePopover': ImagePopover,
'helpDialog': HelpDialog,
'airPopover': AirPopover,
'hintPopover': HintPopover,
'specialCharDialog' : SpecialCharDialog
},

Expand Down
2 changes: 1 addition & 1 deletion dist/summernote.min.js

Large diffs are not rendered by default.

60 changes: 26 additions & 34 deletions examples/plugin-hint-emoji.html → examples/hint-emoji.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<title>summernote</title>
<!-- include jquery -->
<script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.js"></script>

<!-- include libraries BS3 -->
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css" />
Expand All @@ -25,53 +25,45 @@

<script type="text/javascript" src="../dist/summernote.js"></script>
<script type="text/javascript" src="../lang/summernote-ko-KR.js"></script>
<script type="text/javascript" src="../plugin/summernote-ext-hint.js"></script>

<script type="text/javascript">
$(document).ready(function () {
$('.summernote').summernote({
height: 200,
plugin: {
hint: {
loadEmoji: function (data) {
this.emoji = Object.keys(data);
this.emojiLink = data;
},
var self = this;

load: function ($popover) {
var self = this;
$.getJSON('https://api.github.com/emojis', function (data) {
self.loadEmoji(data);
});
},
// load github's emoji list
$.ajax({
url: 'https://api.github.com/emojis'
}).then(function (data) {
var emojis = Object.keys(data);
var emojiUrls = data;

content: function (item) {
var url = this.emojiLink[item];
if (url) {
return $('<img />').attr('src', url).css({width: 20})[0];
}
return '';
$('.summernote').summernote({
height: 300,
hint: [{
search: function (keyword, callback) {
callback($.grep(emojis, function (item) {
return item.indexOf(keyword) === 0;
}));
},

match: /\B:([\-+\w]+)$/,
template: function (item) {
var content = this.emojiLink[item];
var content = emojiUrls[item];
return '<img src="' + content + '" width="20" /> :' + item + ':';
},

match: /\B:([\-+\w]+)$/,

search: function (keyword, callback) {
callback($.grep(this.emoji, function (item) {
return item.indexOf(keyword) === 0;
}));
content: function (item) {
var url = emojiUrls[item];
if (url) {
return $('<img />').attr('src', url).css('width', 20)[0];
}
return '';
}
}
}
}]
});
});
});
</script>
</head>
<body>
<textarea class="summernote">Type text start with ":". For example, :) or :+1:.</textarea>
<textarea class="summernote">Type text start with ":". For example, :smile or :+1:.</textarea>
</body>
</html>
Original file line number Diff line number Diff line change
Expand Up @@ -25,28 +25,14 @@

<script type="text/javascript" src="../dist/summernote.js"></script>
<script type="text/javascript" src="../lang/summernote-ko-KR.js"></script>
<script type="text/javascript" src="../plugin/summernote-ext-hint.js"></script>

<script src="https://www.google.com/jsapi" type="text/javascript"></script>

<script type="text/javascript">
$(document).ready(function() {
$('.summernote').summernote({
height: 200,
tabsize: 2,
toolbar: [
['style', ['bold', 'italic', 'underline', 'clear']],
['color', ['color']],
['para', ['ul', 'ol', 'paragraph']],
['height', ['height']],
['table', ['table']]
],
plugin : {
hint : {
load : function($popover) {
$popover.css({ 'max-width' : '500px' })
},

hint : {
content : function(item) {
return "[" + item.full_name + "] " + item.description;
},
Expand All @@ -62,7 +48,6 @@
callback(data.items);
});
}
}
}
});
});
Expand Down

0 comments on commit 2579963

Please sign in to comment.