UNPKG

wed

Version:

Wed is a schema-aware editor for XML documents.

325 lines 14.9 kB
var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; define(["require", "exports", "jquery", "merge-options", "salve", "wed", "wed/modes/generic/generic", "wed/modes/generic/generic-decorator"], function (require, exports, jquery_1, merge_options_1, salve_1, wed_1, generic_1, generic_decorator_1) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); jquery_1 = __importDefault(jquery_1); merge_options_1 = __importDefault(merge_options_1); var ContextMenu = wed_1.gui.contextMenu.ContextMenu; const { childrenByClass, closestByClass, indexOf } = wed_1.domutil; // tslint:disable-next-line:completed-docs class Validator { constructor(dataRoot) { this.dataRoot = dataRoot; } validateDocument() { return [{ error: new salve_1.ValidationError("Test"), node: this.dataRoot, index: 0, }]; } } // tslint:disable-next-line:completed-docs class TestDecorator extends generic_decorator_1.GenericDecorator { constructor() { super(...arguments); this.elementLevel = { term: 2, ref: 2, text: 1, }; } addHandlers() { super.addHandlers(); wed_1.inputTriggerFactory.makeSplitMergeInputTrigger(this.editor, this.mode, wed_1.GUISelector.fromDataSelector("hi", this.mode.getAbsoluteNamespaceMappings()), wed_1.key.makeKey(";"), wed_1.keyConstants.BACKSPACE, wed_1.keyConstants.DELETE); } // tslint:disable:no-jquery-raw-elements elementDecorator(root, el) { if (this.editor.modeTree.getMode(el) !== this.mode) { // The element is not governed by this mode. return; } const dataNode = this.editor.toDataNode(el); const rend = dataNode.getAttribute("rend"); const localName = dataNode.localName; const inTEI = dataNode.namespaceURI === this.namespaces.tei; let level = inTEI ? this.elementLevel[localName] : undefined; if (level === undefined) { level = 1; } const isP = inTEI && localName === "p"; const isRef = inTEI && localName === "ref"; // We don't run the default when we wrap p. if (!(isP && rend === "wrap")) { // There's no super.super syntax we can use here. wed_1.Decorator.prototype.elementDecorator.call(this, root, el, level, this.contextMenuHandler.bind(this, true), this.contextMenuHandler.bind(this, false)); } if (isRef) { jquery_1.default(el).children("._text._phantom").remove(); this.guiUpdater.insertBefore(el, jquery_1.default("<div class='_text _phantom _end_wrapper'>)</div>")[0], el.lastChild); const $before = jquery_1.default("<div class='_text _phantom _start_wrapper'>(</div>"); this.guiUpdater.insertBefore(el, $before[0], el.firstChild.nextSibling); $before.on("wed-context-menu", { node: el }, this._navigationContextMenuHandler.bind(this)); $before[0].setAttribute("data-wed--custom-context-menu", "true"); } if (isP) { switch (rend) { case "foo": jquery_1.default(el).children("._gui_test").remove(); this.guiUpdater .insertBefore(el, jquery_1.default("<div class='_gui _phantom _gui_test btn " + "btn-default'>Foo</div>")[0], el.lastChild); let found; let child = dataNode.firstElementChild; while (found === undefined && child !== null) { if (child.tagName === "abbr") { found = child; } child = child.nextElementSibling; } if (found !== undefined) { this.guiUpdater .insertBefore(el, jquery_1.default("<div class='_gui _phantom _gui_test btn " + "btn-default'>Foo2</div>")[0], el.lastChild); this.guiUpdater .insertBefore(el, jquery_1.default("<div class='_gui _phantom _gui_test btn " + "btn-default'>Foo3</div>")[0], el.lastChild); } break; case "wrap": if (closestByClass(el, "_gui_test") !== null) { break; } const toRemove = childrenByClass(el, "_gui"); for (const remove of toRemove) { el.removeChild(remove); } const wrapper = jquery_1.default("<div class='_gui _phantom_wrap _gui_test btn " + "btn-default'></div>")[0]; this.guiUpdater.insertBefore(el.parentNode, wrapper, el); this.guiUpdater.insertBefore(wrapper, el, null); break; default: } } } _navigationContextMenuHandler(wedEv, ev) { // node is the node in the GUI tree which corresponds to the navigation item // for which a context menu handler was required by the user. const node = wedEv.data.node; const dataNode = this.editor.toDataNode(node); const prefixedName = this.mode.unresolveName(new salve_1.EName(dataNode.namespaceURI === null ? "" : dataNode.namespaceURI, dataNode.localName)); // We don't know this element. if (prefixedName === undefined) { return true; } // container, offset: location of the node in its parent. const container = node.parentNode; const offset = indexOf(container.childNodes, node); // Create "insert" transformations for siblings that could be inserted // before this node. const actions = this.mode.getContextualActions("insert", prefixedName, container, offset); // data to pass to transformations const data = { name: prefixedName, moveCaretTo: this.editor.caretManager.makeCaret(container, offset), }; const items = []; for (const act of actions) { const text = `${act.getLabelFor(data)} before this one`; const $a = jquery_1.default(`<a tabindex='0' href='#'>${text}</a>`); $a.click(data, act.boundTerminalHandler); items.push(jquery_1.default("<li></li>").append($a)[0]); } // tslint:disable-next-line:no-unused-expression new ContextMenu(this.editor.doc, ev.clientX, ev.clientY, items); return false; } } exports.TestDecorator = TestDecorator; // tslint:disable-next-line:completed-docs class TypeaheadAction extends wed_1.Action { execute() { const editor = this.editor; const substringMatcher = (strs) => { return (q, cb) => { const re = new RegExp(q, "i"); const matches = []; for (const str of strs) { if (re.test(str)) { matches.push(str); } } cb(matches); }; }; const testData = []; for (let i = 0; i < 100; ++i) { testData.push(`Test ${i}`); } const options = { options: { autoselect: true, hint: true, highlight: true, minLength: 1, }, datasets: [{ source: substringMatcher(testData), limit: testData.length, }], }; const typeahead = editor.editingMenuManager.setupTypeaheadPopup(300, "Test", options, (obj) => { if (obj != null) { editor.insertText(obj); } }, undefined, true); typeahead.hideSpinner(); const range = editor.caretManager.range; // This is purposely not as intelligent as what real mode would need. if (range != null && !range.collapsed) { typeahead.setValue(range.toString()); } } } // tslint:disable-next-line:completed-docs class DraggableModalAction extends wed_1.Action { get modal() { if (this._modal === undefined) { this._modal = this.editor.makeModal({ draggable: true }); } return this._modal; } execute() { this.modal.modal(); } } // tslint:disable-next-line:completed-docs class DraggableResizableModalAction extends wed_1.Action { get modal() { if (this._modal === undefined) { this._modal = this.editor.makeModal({ resizable: true, draggable: true, }); } return this._modal; } execute() { this.modal.modal(); } } // tslint:disable-next-line:completed-docs class ResizableModalAction extends wed_1.Action { get modal() { if (this._modal === undefined) { this._modal = this.editor.makeModal({ resizable: true }); } return this._modal; } execute() { this.modal.modal(); } } /** * This mode is purely designed to help test wed, and nothing * else. Don't derive anything from it and don't use it for editing. */ class TestMode extends generic_1.Mode { constructor(editor, options) { super(editor, options); this.optionTemplate = { metadata: true, autoinsert: false, ambiguous_fileDesc_insert: false, fileDesc_insert_needs_input: false, hide_attributes: false, // We use nameSuffix to vary the name given to multiple instances. nameSuffix: false, stylesheets: false, }; this.wedOptions = merge_options_1.default({}, this.wedOptions); const suffix = options.nameSuffix != null ? options.nameSuffix : ""; this.wedOptions.metadata = { name: `Test${suffix}`, authors: ["Louis-Dominique Dubeau"], description: "TEST MODE. DO NOT USE IN PRODUCTION!", license: "MPL 2.0", copyright: "Mangalam Research Center for Buddhist Languages", }; this.wedOptions.label_levels = { max: 2, initial: 1, }; if (options.hide_attributes) { this.wedOptions.attributes = "hide"; } else { this.wedOptions.attributes = { handling: "edit", autohide: { method: "selector", elements: [{ selector: "div", attributes: ["*", { except: ["sample", "type", "subtype"], }], }], }, }; } this.typeaheadAction = new TypeaheadAction(editor, "Test typeahead", undefined, "<i class='fa fa-plus fa-fw'></i>", true); this.draggableAction = new DraggableModalAction(editor, "Test draggable", undefined, undefined, true); this.resizableAction = new ResizableModalAction(editor, "Test resizable", undefined, undefined, true); this.draggableResizableAction = new DraggableResizableModalAction(editor, "Test draggable resizable", undefined, undefined, true); } getStylesheets() { const stylesheets = this.options.stylesheets; return stylesheets !== undefined ? stylesheets : []; } getToolbarButtons() { return [this.typeaheadAction.makeButton()]; } getContextualActions(transformationType, tag, container, offset) { if (this.options.fileDesc_insert_needs_input && tag === "fileDesc" && transformationType === "insert") { return [new wed_1.transformation.Transformation(this.editor, "insert", "foo", // We don't need a real handler because it will not be called. // tslint:disable-next-line:no-empty () => { }, { needsInput: true })]; } let ret = super.getContextualActions(transformationType, tag, container, offset); if (this.options.ambiguous_fileDesc_insert && tag === "fileDesc" && transformationType === "insert") { // We just duplicate the transformation. ret = ret.concat(ret); } if (tag === "ref" && (transformationType === "insert" || transformationType === "wrap")) { // It is a bit peculiar to tie the draggable and resizable actions to // "ref", because it is not necessary, but meh... ret.push(this.typeaheadAction, this.draggableAction, this.resizableAction, this.draggableResizableAction); } return ret; } makeDecorator() { return new TestDecorator(this, this.editor, this.metadata, this.options); } getAttributeCompletions(attr) { if (attr.name === "n") { return ["completion1", "completion2"]; } return []; } getValidator() { return new Validator(this.editor.dataRoot); } } exports.TestMode = TestMode; exports.Mode = TestMode; }); // LocalWords: Dubeau MPL Mangalam tei domutil btn getLabelFor tabindex href // LocalWords: li nameSuffix subtype typeahead fw draggable resizable //# sourceMappingURL=test-mode.js.map