
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
/**
* TinyMCE version 7.2.1 (2024-07-03)
*/
(function () {
'use strict';
var global$2 = tinymce.util.Tools.resolve('tinymce.PluginManager');
var global$1 = tinymce.util.Tools.resolve('tinymce.dom.RangeUtils');
var global = tinymce.util.Tools.resolve('tinymce.util.Tools');
const option = name => editor => editor.options.get(name);
const register$2 = editor => {
const registerOption = editor.options.register;
registerOption('allow_html_in_named_anchor', {
processor: 'boolean',
default: false
});
};
const allowHtmlInNamedAnchor = option('allow_html_in_named_anchor');
const namedAnchorSelector = 'a:not([href])';
const isEmptyString = str => !str;
const getIdFromAnchor = elm => {
const id = elm.getAttribute('id') || elm.getAttribute('name');
return id || '';
};
const isAnchor = elm => elm.nodeName.toLowerCase() === 'a';
const isNamedAnchor = elm => isAnchor(elm) && !elm.getAttribute('href') && getIdFromAnchor(elm) !== '';
const isEmptyNamedAnchor = elm => isNamedAnchor(elm) && !elm.firstChild;
const removeEmptyNamedAnchorsInSelection = editor => {
const dom = editor.dom;
global$1(dom).walk(editor.selection.getRng(), nodes => {
global.each(nodes, node => {
if (isEmptyNamedAnchor(node)) {
dom.remove(node, false);
}
});
});
};
const isValidId = id => /^[A-Za-z][A-Za-z0-9\-:._]*$/.test(id);
const getNamedAnchor = editor => editor.dom.getParent(editor.selection.getStart(), namedAnchorSelector);
const getId = editor => {
const anchor = getNamedAnchor(editor);
if (anchor) {
return getIdFromAnchor(anchor);
} else {
return '';
}
};
const createAnchor = (editor, id) => {
editor.undoManager.transact(() => {
if (!allowHtmlInNamedAnchor(editor)) {
editor.selection.collapse(true);
}
if (editor.selection.isCollapsed()) {
editor.insertContent(editor.dom.createHTML('a', { id }));
} else {
removeEmptyNamedAnchorsInSelection(editor);
editor.formatter.remove('namedAnchor', undefined, undefined, true);
editor.formatter.apply('namedAnchor', { value: id });
editor.addVisual();
}
});
};
const updateAnchor = (editor, id, anchorElement) => {
anchorElement.removeAttribute('name');
anchorElement.id = id;
editor.addVisual();
editor.undoManager.add();
};
const insert = (editor, id) => {
const anchor = getNamedAnchor(editor);
if (anchor) {
updateAnchor(editor, id, anchor);
} else {
createAnchor(editor, id);
}
editor.focus();
};
const insertAnchor = (editor, newId) => {
if (!isValidId(newId)) {
editor.windowManager.alert('ID should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.');
return false;
} else {
insert(editor, newId);
return true;
}
};
const open = editor => {
const currentId = getId(editor);
editor.windowManager.open({
title: 'Anchor',
size: 'normal',
body: {
type: 'panel',
items: [{
name: 'id',
type: 'input',
label: 'ID',
placeholder: 'example'
}]
},
buttons: [
{
type: 'cancel',
name: 'cancel',
text: 'Cancel'
},
{
type: 'submit',
name: 'save',
text: 'Save',
primary: true
}
],
initialData: { id: currentId },
onSubmit: api => {
if (insertAnchor(editor, api.getData().id)) {
api.close();
}
}
});
};
const register$1 = editor => {
editor.addCommand('mceAnchor', () => {
open(editor);
});
};
const isNamedAnchorNode = node => isEmptyString(node.attr('href')) && !isEmptyString(node.attr('id') || node.attr('name'));
const isEmptyNamedAnchorNode = node => isNamedAnchorNode(node) && !node.firstChild;
const setContentEditable = state => nodes => {
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i];
if (isEmptyNamedAnchorNode(node)) {
node.attr('contenteditable', state);
}
}
};
const setup = editor => {
editor.on('PreInit', () => {
editor.parser.addNodeFilter('a', setContentEditable('false'));
editor.serializer.addNodeFilter('a', setContentEditable(null));
});
};
const registerFormats = editor => {
editor.formatter.register('namedAnchor', {
inline: 'a',
selector: namedAnchorSelector,
remove: 'all',
split: true,
deep: true,
attributes: { id: '%value' },
onmatch: (node, _fmt, _itemName) => {
return isNamedAnchor(node);
}
});
};
const onSetupEditable = editor => api => {
const nodeChanged = () => {
api.setEnabled(editor.selection.isEditable());
};
editor.on('NodeChange', nodeChanged);
nodeChanged();
return () => {
editor.off('NodeChange', nodeChanged);
};
};
const register = editor => {
const onAction = () => editor.execCommand('mceAnchor');
editor.ui.registry.addToggleButton('anchor', {
icon: 'bookmark',
tooltip: 'Anchor',
onAction,
onSetup: buttonApi => {
const unbindSelectorChanged = editor.selection.selectorChangedWithUnbind('a:not([href])', buttonApi.setActive).unbind;
const unbindEditableChanged = onSetupEditable(editor)(buttonApi);
return () => {
unbindSelectorChanged();
unbindEditableChanged();
};
}
});
editor.ui.registry.addMenuItem('anchor', {
icon: 'bookmark',
text: 'Anchor...',
onAction,
onSetup: onSetupEditable(editor)
});
};
var Plugin = () => {
global$2.add('anchor', editor => {
register$2(editor);
setup(editor);
register$1(editor);
register(editor);
editor.on('PreInit', () => {
registerFormats(editor);
});
});
};
Plugin();
})();