Перелинковка статей с помощью виджета для django-summernote

90 0

В своих проектах в качестве редактора WYSIWYG использую удобный, встраиваемый в Django редактор summernote.

Встраивается он приложением django-summernote. Приложение поддерживает загрузку изображений через django в редактируемые тексты.

Но данный пост не об этом. 

Сегодня я расскажу как я реализовал удобную перелинковку статей этого блога с помощью виджета для summernote.

---

Про установку и настройку django-summernote писать не буду там все просто.

Приступим сразу к созданию нашего виджета для перелинковки.

1. Делаем модель для хранения ключевых слов или фраз для перелинковки.

class LinkWords(models.Model):
post = models.ForeignKey(MyPostModel, # Модель с нашими постами
verbose_name=('Пост'),
related_name='linkwords')
word = models.CharField('Ключевое словао/фраза',
max_length=100,
unique=True)
class Meta:
verbose_name='Ключевое слово/фраза'
verbose_name_plural='Ключевые слова/фразы'
ordering = ['word']
def __str__(self):
return self.word

2. Пишем представление для вывода списка ключевых слов и ссылок на страницы

# Доступ к представлению открыт только для superuser
# Для разграничения наследуем класс django-braces или другим способом
class LinkWordsView(SuperuserRequiredMixin, View):
http_method_names = ['get']
context_object_name = 'linkwords'
def get(self, request, *args, **kwargs):
qs = LinkWords.objects.all().values_list(
'post__category__slug',
'post__slug',
'word'
)
items = ['мои услуги'] # Можем добавить слова константы
urls = ['/services/'] # и ссылки константы
for i in qs:
items.append(i[2])
urls.append('/{0}/{1}/'.format(i[0], i[1]))
response = json.dumps([items, urls])
return HttpResponse(response)

3. Добавляем урл в urls.py и проверяем отображение списка по соответствующему адресу.

urlpatterns = [
...
url(r'^linkwords/$',
LinkWordsJsonView.as_view(),
name='linkwords'),
    ...
]

4. Пишем код виджета для редактора

/**
* Виджет summernote для вставки ссылок вокруг выделенного текста в редакторе
*/
(function (factory) {
if (typeof define === 'function' && define.amd) {
define(['jquery'], factory);
} else if (typeof module === 'object' && module.exports) {
module.exports = factory(require('jquery'));
} else {
factory(window.jQuery);
}
}(function ($) {
$.extend($.summernote.plugins, {
'linkwords': function (context) {
var ui = $.summernote.ui;
var options = context.options.linkwords;
var context_options = context.options;
var defaultOptions = {
label: 'Перелинковка',
};
            // Функция для оборачивания текста ссылкой
self.wrapInTag = function (url, word) {
if (window.getSelection) {
var selection = window.getSelection(),
selected = (selection.rangeCount > 0) && selection.getRangeAt(0);
if (selected.startOffset !== selected.endOffset) {
var range = selected.cloneRange();
var startParentElement = range.startContainer.parentElement;
var endParentElement = range.endContainer.parentElement;
if( ! startParentElement.isSameNode(endParentElement)) {
if ( ! self.isSelectionParsable(startParentElement, endParentElement)) {
return;
}
}
var newNode = document.createElement('a'); //url, word
newNode.setAttribute('href', url);
newNode.setAttribute('alt', word);
newNode.appendChild(range.extractContents());
range.insertNode(newNode)
range.selectNodeContents(newNode);
selection.removeAllRanges();
selection.addRange(range);
}
}
};
            # Код виджета
context.memo('button.linkwords', function () {
                # Получаем список слов и ссылок, формируем html и вставляем в выпадающее меню
$.get('/linkwords/', function(data) {
lst = JSON.parse(data);
list = '';
for (i = 0; i < lst[0].length; i++) {
list += '<li><a href="#" data-value="' + lst[1][i] + '" data-alt="' + lst[0][i] + '">' + lst[0][i] + '</a></li>';
};
$(".dropdown-linkwords").html(list);
});
                # Формируем поле с выпадающим списком для меню редактора
var button = ui.buttonGroup([
ui.button({
className: 'dropdown-toggle',
contents: '<span class="linkwords">' + defaultOptions.label + ' </span><span class="note-icon-caret"></span>',
tooltip: defaultOptions.tooltip,
data: {
toggle: 'dropdown'
}
}),
ui.dropdown({
className: 'dropdown-linkwords',
click: function (event) {
event.preventDefault();
var $button = $(event.target);
var url = $button.data('value');
var btn_val = $button.data('alt');
console.log($button.data('alt'));
var node = document.createElement('a');
self.wrapInTag(url, btn_val);
}
})
]);
return button.render();
});
}
});
}));

5. Добавляем виджет в settings.py

SUMMERNOTE_CONFIG = {
    ...
'toolbar': [
        # Виджеты меню редактора по умолчанию
["style", ["style"]],
["font", ["bold",
"italic",
"underline",
"superscript",
"subscript",
"strikethrough",
"clear"]],
["fontname", ["fontname"]],
["fontsize", ["fontsize"]],
["color", ["color"]],
["para", ["ul", "ol", "paragraph"]],
["height", ["height"]],
["table", ["table"]],
["insert", ["link", "picture", "video", "hr"]],
["view", ["fullscreen", "codeview"]],
["help", ["help"]],
        # Наш виджет для перелинковки
['insert', ['linkwords']],
],
'js': (
        # Путь к нашему коду виджета
'/static/js/linkwords.js',
),
}

В результате наших манипуляций получим удобный инструмент для перелинковки статей в блоге или на сайте.

Дарю! ))

Пользуйтесь.

Комментарии

Контактные данные

+7 (903) 612-13-42
 Россия, г. Москва