bibcite_footnotes-8.x-1.0-beta3/js/bibciteFootnotes.js
js/bibciteFootnotes.js
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports === 'object')
exports["CKEditor5"] = factory();
else
root["CKEditor5"] = root["CKEditor5"] || {}, root["CKEditor5"]["bibciteFootnotes"] = factory();
})(self, () => {
return /******/ (() => { // webpackBootstrap
/******/ var __webpack_modules__ = ({
/***/ "./js/ckeditor5_plugins/bibciteFootnotes/src/bibciteFootnotes.js":
/*!***********************************************************************!*\
!*** ./js/ckeditor5_plugins/bibciteFootnotes/src/bibciteFootnotes.js ***!
\***********************************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ BibciteFootnotes)
/* harmony export */ });
/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ "ckeditor5/src/core.js");
/* harmony import */ var ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ckeditor5/src/ui */ "ckeditor5/src/ui.js");
/* harmony import */ var ckeditor5_src_widget__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ckeditor5/src/widget */ "ckeditor5/src/widget.js");
class BibciteFootnotes extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin {
_currentElement = null;
_references = [];
static get requires() {
return [ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__.ContextualBalloon, ckeditor5_src_widget__WEBPACK_IMPORTED_MODULE_2__.Widget];
}
init() {
const editor = this.editor;
const t = editor.t;
this._balloon = editor.plugins.get(ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__.ContextualBalloon);
// Initialize references immediately
this._loadReferences();
// Register the schema
editor.model.schema.register('bibciteFootnote', {
inheritAllFrom: '$inlineObject',
allowAttributes: ['entityId', 'pageRange']
});
this._setupSimpleConversion();
// Add Alt+C keyboard shortcut
editor.keystrokes.set('Alt+C', (data, cancel) => {
const selection = editor.model.document.selection;
const selectedElement = selection.getSelectedElement();
if (selectedElement && selectedElement.is('element', 'bibciteFootnote')) {
this.showUI(selectedElement);
} else {
this.showUI();
}
cancel();
});
// UI component factory
editor.ui.componentFactory.add('bibciteFootnotes', locale => {
const button = new ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__.ButtonView(locale);
button.set({
label: t('Cite'),
withText: true,
tooltip: t('Insert citation (Alt+C)'),
});
button.on('execute', () => {
this.showUI();
});
return button;
});
// Click and keyboard handlers
this.listenTo(editor.editing.view.document, 'click', (evt, data) => {
const modelElement = editor.editing.mapper.toModelElement(data.target);
if (modelElement?.is('element', 'bibciteFootnote')) {
this.showUI(modelElement);
}
});
this.listenTo(editor.editing.view.document, 'keydown', (evt, data) => {
const modelElement = editor.editing.mapper.toModelElement(data.target);
if (modelElement?.is('element', 'bibciteFootnote')) {
if (data.keyCode === 13 || data.keyCode === 32) {
data.preventDefault();
this.showUI(modelElement);
}
}
});
editor.accessibility.addKeystrokeInfos({
keystrokes: [
{
label: t('Insert citation'),
keystroke: "Alt+c",
}
]
});
}
_loadReferences() {
try {
this._references = window.parent.drupalSettings?.bibcite_footnotes?.references || [];
} catch (e) {
console.error('Could not access Drupal settings:', e);
}
}
_setupSimpleConversion() {
const editor = this.editor;
const truncateText = (text, maxLength = 20) => {
if (!text || text.length <= maxLength) return text;
const commaIndex = text.substring(0, maxLength).lastIndexOf(',');
if (commaIndex > 0 && commaIndex <= maxLength) {
return text.substring(0, commaIndex) + '…';
}
const spaceIndex = text.substring(0, maxLength).lastIndexOf(' ');
if (spaceIndex > 0 && spaceIndex <= maxLength) {
return text.substring(0, spaceIndex) + '…';
}
return text.substring(0, maxLength - 1) + '…';
};
// Create a mapping of entity IDs to reference titles
const referenceMap = {};
this._references.forEach(ref => {
referenceMap[ref[1]] = ref[0];
});
// Editing downcast
editor.conversion.for('editingDowncast').elementToElement({
model: 'bibciteFootnote',
view: (modelElement, { writer }) => {
const entityId = modelElement.getAttribute('entityId');
const pageRange = modelElement.getAttribute('pageRange');
const fullTitle = referenceMap[entityId] || `Citation ${entityId}`;
const truncatedTitle = truncateText(fullTitle);
const labelText = `Citation: ${fullTitle}${pageRange ? ', pages ' + pageRange : ''}`;
const visibleText = pageRange ?
`[${truncatedTitle}, pp. ${pageRange}]` :
`[${truncatedTitle}]`;
const span = writer.createContainerElement(
'span',
{
class: 'bibcite-footnote-placeholder',
role: 'button',
'aria-haspopup': 'dialog',
'aria-label': labelText,
tabindex: '0'
},
writer.createText(visibleText)
);
return (0,ckeditor5_src_widget__WEBPACK_IMPORTED_MODULE_2__.toWidget)(span, writer, { label: labelText });
}
});
// Data downcast for output
editor.conversion.for('dataDowncast').elementToElement({
model: 'bibciteFootnote',
view: (modelElement, { writer }) => {
const entityId = modelElement.getAttribute('entityId');
const pageRange = modelElement.getAttribute('pageRange') || '';
return writer.createContainerElement('bibcite-footnote', {
'data-entity-id': entityId,
'data-page-range': pageRange
});
}
});
// Upcast conversion
editor.conversion.for('upcast').elementToElement({
view: {
name: 'bibcite-footnote',
attributes: ['data-entity-id']
},
model: (viewElement, { writer }) => {
return writer.createElement('bibciteFootnote', {
entityId: viewElement.getAttribute('data-entity-id'),
pageRange: viewElement.getAttribute('data-page-range') || ''
});
}
});
}
_createFormView() {
const editor = this.editor;
const t = editor.t;
const formView = new ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__.View(editor.locale);
formView.saveButtonView = new ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__.ButtonView(editor.locale);
formView.saveButtonView.set({
label: t('Save'),
withText: true,
class: 'ck-button-save'
});
formView.saveButtonView.on('execute', () => {
this._handleFormSubmit();
});
formView.cancelButtonView = new ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__.ButtonView(editor.locale);
formView.cancelButtonView.set({
label: t('Cancel'),
withText: true,
class: 'ck-button-cancel'
});
formView.cancelButtonView.on('execute', () => {
this._hideUI();
});
// Create a simple template that we can update dynamically
formView.setTemplate({
tag: 'div',
attributes: {
class: ['ck', 'ck-bibcite-form'],
tabindex: '-1',
},
children: [
{
tag: 'div',
attributes: { class: ['ck', 'ck-bibcite-form__row'] },
children: [
{
tag: 'label',
attributes: { for: 'work-select', class: ['ck', 'ck-label'] },
children: [t('Work to cite')]
},
{
tag: 'select',
attributes: {
class: ['ck', 'ck-input', 'ck-bibcite-work-select'],
id: 'work-select',
},
children: [] // Will be populated dynamically
}
]
},
{
tag: 'div',
attributes: { class: ['ck', 'ck-bibcite-form__row'] },
children: [
{
tag: 'label',
attributes: { for: 'page-input', class: ['ck', 'ck-label'] },
children: [t('Page(s)')]
},
{
tag: 'input',
attributes: {
class: ['ck', 'ck-input', 'ck-bibcite-page-input'],
type: 'text',
id: 'page-input',
placeholder: t('e.g., 42-45'),
}
}
]
},
{
tag: 'div',
attributes: { class: ['ck', 'ck-bibcite-form__actions'] },
children: [
formView.cancelButtonView,
formView.saveButtonView
]
}
]
});
// Add keydown event listener for Escape and Enter keys
formView.on('render', () => {
if (formView.element) {
formView.element.addEventListener('keydown', (event) => {
if (event.key === 'Escape') {
event.preventDefault();
event.stopPropagation();
this._hideUI();
} else if (event.key === 'Enter') {
event.preventDefault();
event.stopPropagation();
this._handleFormSubmit();
}
});
}
});
return formView;
}
_updateFormViewReferences() {
if (!this.formView || !this.formView.element) {
return;
}
const workSelect = this.formView.element.querySelector('.ck-bibcite-work-select');
if (!workSelect) {
return;
}
// Store current selection
const currentSelection = workSelect.value;
// Clear all options
workSelect.innerHTML = '';
// Add default option
const defaultOption = document.createElement('option');
defaultOption.value = '';
defaultOption.textContent = this.editor.t('-- Select --');
workSelect.appendChild(defaultOption);
// Add current references
this._references.forEach(ref => {
const option = document.createElement('option');
option.value = ref[1];
option.textContent = ref[0];
workSelect.appendChild(option);
});
// Restore selection if possible
if (currentSelection && Array.from(workSelect.options).some(opt => opt.value === currentSelection)) {
workSelect.value = currentSelection;
} else if (this._currentElement) {
const entityId = this._currentElement.getAttribute('entityId');
if (entityId && Array.from(workSelect.options).some(opt => opt.value === entityId)) {
workSelect.value = entityId;
}
}
console.log('Dropdown updated with', this._references.length, 'references');
}
showUI(modelElement = null) {
this._currentElement = modelElement;
// Always reload references and update the form when showing UI
this._loadReferences();
// Create form view if it doesn't exist
if (!this.formView) {
this.formView = this._createFormView();
}
// Update the form view with current references
if (!this._balloon.hasView(this.formView)) {
this._balloon.add({
view: this.formView,
position: this._getBalloonPositionData()
});
// Wait for the form to render, then populate the dropdown
setTimeout(() => {
this._updateFormViewReferences();
this._focusForm();
}, 50);
} else {
// Form is already visible, just update it
this._updateFormViewReferences();
this._focusForm();
}
}
_focusForm() {
if (this.formView.element) {
const workSelect = this.formView.element.querySelector('.ck-bibcite-work-select');
const pageInput = this.formView.element.querySelector('.ck-bibcite-page-input');
if (this._currentElement) {
const entityId = this._currentElement.getAttribute('entityId');
if (workSelect) {
workSelect.value = entityId || '';
}
if (pageInput) {
pageInput.value = this._currentElement.getAttribute('pageRange') || '';
}
} else {
if (workSelect) {
workSelect.selectedIndex = 0;
}
if (pageInput) {
pageInput.value = '';
}
}
if (workSelect) {
workSelect.focus();
}
}
}
_handleFormSubmit() {
const editor = this.editor;
const formElement = this.formView.element;
const workSelect = formElement.querySelector('.ck-bibcite-work-select');
const pageInput = formElement.querySelector('.ck-bibcite-page-input');
if (!workSelect) return;
const entityId = workSelect.value;
const pages = pageInput.value.trim();
if (entityId) {
editor.model.change(writer => {
if (this._currentElement) {
writer.setAttribute('entityId', entityId, this._currentElement);
writer.setAttribute('pageRange', pages, this._currentElement);
} else {
const selection = editor.model.document.selection;
const position = selection.getFirstRange().start;
const citationElement = writer.createElement('bibciteFootnote', { entityId, pageRange: pages });
writer.insert(citationElement, position);
}
});
}
this._hideUI();
}
_hideUI() {
if (this.formView && this._balloon.hasView(this.formView)) {
this._balloon.remove(this.formView);
}
this._currentElement = null;
this.editor.editing.view.focus();
}
_getBalloonPositionData() {
const view = this.editor.editing.view;
const target = view.domConverter.viewRangeToDom(
view.document.selection.getFirstRange()
);
return { target };
}
}
/***/ }),
/***/ "ckeditor5/src/core.js":
/*!************************************************************!*\
!*** delegated ./core.js from dll-reference CKEditor5.dll ***!
\************************************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
module.exports = (__webpack_require__(/*! dll-reference CKEditor5.dll */ "dll-reference CKEditor5.dll"))("./src/core.js");
/***/ }),
/***/ "ckeditor5/src/ui.js":
/*!**********************************************************!*\
!*** delegated ./ui.js from dll-reference CKEditor5.dll ***!
\**********************************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
module.exports = (__webpack_require__(/*! dll-reference CKEditor5.dll */ "dll-reference CKEditor5.dll"))("./src/ui.js");
/***/ }),
/***/ "ckeditor5/src/widget.js":
/*!**************************************************************!*\
!*** delegated ./widget.js from dll-reference CKEditor5.dll ***!
\**************************************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
module.exports = (__webpack_require__(/*! dll-reference CKEditor5.dll */ "dll-reference CKEditor5.dll"))("./src/widget.js");
/***/ }),
/***/ "dll-reference CKEditor5.dll":
/*!********************************!*\
!*** external "CKEditor5.dll" ***!
\********************************/
/***/ ((module) => {
"use strict";
module.exports = CKEditor5.dll;
/***/ })
/******/ });
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/************************************************************************/
/******/ /* webpack/runtime/define property getters */
/******/ (() => {
/******/ // define getter functions for harmony exports
/******/ __webpack_require__.d = (exports, definition) => {
/******/ for(var key in definition) {
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ }
/******/ }
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/hasOwnProperty shorthand */
/******/ (() => {
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
/******/ })();
/******/
/******/ /* webpack/runtime/make namespace object */
/******/ (() => {
/******/ // define __esModule on exports
/******/ __webpack_require__.r = (exports) => {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/ })();
/******/
/************************************************************************/
var __webpack_exports__ = {};
// This entry needs to be wrapped in an IIFE because it needs to be in strict mode.
(() => {
"use strict";
/*!************************************************************!*\
!*** ./js/ckeditor5_plugins/bibciteFootnotes/src/index.js ***!
\************************************************************/
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
/* harmony import */ var _bibciteFootnotes__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./bibciteFootnotes */ "./js/ckeditor5_plugins/bibciteFootnotes/src/bibciteFootnotes.js");
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({
BibciteFootnotes: _bibciteFootnotes__WEBPACK_IMPORTED_MODULE_0__["default"]
});
})();
__webpack_exports__ = __webpack_exports__["default"];
/******/ return __webpack_exports__;
/******/ })()
;
});
//# sourceMappingURL=bibciteFootnotes.js.map