Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions dialogs/contents.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/**
* Copyright (c) 2014-2016, CKSource - Frederico Knabben. All rights reserved.
* Licensed under the terms of the MIT License (see LICENSE.md).
*/

// Note: This automatic widget to dialog window binding (the fact that every field is set up from the widget
// and is committed to the widget) is only possible when the dialog is opened by the Widgets System
// (i.e. the widgetDef.dialog property is set).
// When you are opening the dialog window by yourself, you need to take care of this by yourself too.

CKEDITOR.dialog.add('contents', function (editor) {
return {
title: 'Edit',
minWidth: 200,
minHeight: 100,
contents: [
{
id: 'info',
elements: [
{
id: 'align',
type: 'select',
label: 'Align',
items: [
[editor.lang.common.notSet, ''],
[editor.lang.common.alignLeft, 'float-left'],
[editor.lang.common.alignRight, 'float-right'],
],
'default': editor.lang.common.notSet,
// When setting up this field, set its value to the "align" value from widget data.
// Note: Align values used in the widget need to be the same as those defined in the "items" array above.
setup: function (widget) {
widget.data.align === undefined ? this.setValue('') : this.setValue(widget.data.align);
},
// When committing (saving) this field, set its value to the widget data.
commit: function (widget) {
widget.setData('align', this.getValue());
}
},

{
id: 'chkInsertOpt',
type: 'checkbox',
label: 'Ignore nested headers',
'default': true,
setup: function (widget) {
widget.data.chkInsertOpt === undefined ? this.setValue(false) : this.setValue(widget.data.chkInsertOpt);
},

commit: function (widget) {
widget.setData('chkInsertOpt', this.getValue());
}
}
]
},
]
};
});
Binary file added icons/contents.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
132 changes: 132 additions & 0 deletions plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
CKEDITOR.plugins.add('contents', {
requires: 'widget',

icons: 'contents',

init: function (editor) {
editor.addContentsCss(this.path + 'styles/styles.css');
CKEDITOR.dialog.add('contents', this.path + 'dialogs/contents.js');

// Default Config
var defaultConfig = {
header: '<p class="toc-title">Contents</p>',
//ol or ul
listType: 'ol',
headersSelector: '> h1,> h2,> h3,> h4,> h5,> h6,',
nestedHeadersSelector: 'h1,h2,h3,h4,h5,h6,'
};

// Get Config
var config = CKEDITOR.tools.extend(defaultConfig, editor.config.contents || {}, true);

editor.widgets.add('contents', {
button: 'Insert Table of Contents',

template:
'<div class="widget-toc"></div>',

allowedContent:
'div(!widget-toc,float-left,float-right,align-center);' +
'p(!toc-title);',

dialog: 'contents',

upcast: function (element) {
return element.name == 'div'
&& element.hasClass('widget-toc');
},

init: function () {
editor.on('saveSnapshot', function (evt) {
buildToc(this.element)
}.bind(this));

this.on('focus', function (evt) {
buildToc(this.element)
}.bind(this));

buildToc(this.element);

if (this.element.hasClass('float-left'))
this.setData('align', 'float-left');
if (this.element.hasClass('float-right'))
this.setData('align', 'float-right');
if (this.element.hasClass('toc_root'))
this.setData('chkInsertOpt', true);
},

data: function () {
this.element.removeClass('float-left');
this.element.removeClass('float-right');
this.element.removeClass('toc_root');
if (this.data.align)
this.element.addClass(this.data.align);

if (this.data.chkInsertOpt)
this.element.addClass('toc_root');
},
});

function buildToc(element) {

element.setHtml(config.header);

Container = new CKEDITOR.dom.element(config.listType);
Container.appendTo(element);

if (element.hasClass('toc_root')) {
findRoot = config.headersSelector;
} else {
findRoot = config.nestedHeadersSelector;
}

var headings = editor.editable().find(findRoot),
parentLevel = 1,
length = headings.count();

//get each heading
for (var i = 0; i < length; ++i) {

var currentHeading = headings.getItem(i),
text = currentHeading.getText(),
newLevel = parseInt(currentHeading.getName().substr(1, 1));
var diff = (newLevel - parentLevel);

//set the start level in case it is not h1
if (i === 0) {
diff = 0;
parentLevel = newLevel;
}

//we need a new ul if the new level has a higher number than its parents number
if (diff > 0) {
var containerLiNode = Container.getLast();
var ulNode = new CKEDITOR.dom.element(config.listType);
ulNode.appendTo(containerLiNode);
Container = ulNode;
parentLevel = newLevel;
}

//we need to get a previous ul if the new level has a lower number than its parents number
if (diff < 0) {
while (0 !== diff++) {
parent = Container.getParent().getParent();
Container = (parent.getName() === config.listType ? parent : Container);
}
parentLevel = newLevel;
}

if (text == null || text.trim() === '') {
text = '&nbsp;'
}

var id = text.replace(/[^A-Za-z0-9_\-]+/g, '+');
currentHeading.setAttribute('id', id);

var liNode = CKEDITOR.dom.element.createFromHtml('<li><a href="#' + id + '">' + text + '</a></li>');

liNode.appendTo(Container);
}
}
}
});
34 changes: 34 additions & 0 deletions styles/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
.widget-toc{

display: table;
border: 1px solid #a2a9b1;
background-color: #f8f9fa;
padding-right: 1rem;
font-size: 95%;
}

.widget-toc ol {
padding-right: 0px;
counter-reset: item;
}
.widget-toc ol li {
display: block;
position: relative;
}
.widget-toc ol li:before {
content: counters(item, ".");
counter-increment: item;
position: absolute;
margin-right: 100%;
right: 0.5rem;
}


.toc-title{

text-align: center;
font-weight: 700;
margin: 0;
padding: 0;

}