forked from extern/bruno
113 lines
3.3 KiB
JavaScript
113 lines
3.3 KiB
JavaScript
|
/**
|
||
|
* Copyright (c) 2021 GraphQL Contributors.
|
||
|
*
|
||
|
* This source code is licensed under the MIT license found in the
|
||
|
* LICENSE file in the root directory of this source tree.
|
||
|
*/
|
||
|
import escapeHTML from 'escape-html';
|
||
|
import MD from 'markdown-it';
|
||
|
|
||
|
import {
|
||
|
GraphQLNonNull,
|
||
|
GraphQLList,
|
||
|
GraphQLType,
|
||
|
GraphQLField,
|
||
|
} from 'graphql';
|
||
|
|
||
|
const md = new MD();
|
||
|
|
||
|
/**
|
||
|
* Render a custom UI for CodeMirror's hint which includes additional info
|
||
|
* about the type and description for the selected context.
|
||
|
*/
|
||
|
export default function onHasCompletion(
|
||
|
_cm,
|
||
|
data,
|
||
|
onHintInformationRender,
|
||
|
) {
|
||
|
const CodeMirror = require('codemirror');
|
||
|
|
||
|
let information;
|
||
|
let deprecation;
|
||
|
|
||
|
// When a hint result is selected, we augment the UI with information.
|
||
|
CodeMirror.on(
|
||
|
data,
|
||
|
'select',
|
||
|
(ctx, el) => {
|
||
|
// Only the first time (usually when the hint UI is first displayed)
|
||
|
// do we create the information nodes.
|
||
|
if (!information) {
|
||
|
const hintsUl = el.parentNode;
|
||
|
|
||
|
// This "information" node will contain the additional info about the
|
||
|
// highlighted typeahead option.
|
||
|
information = document.createElement('div');
|
||
|
information.className = 'CodeMirror-hint-information';
|
||
|
hintsUl.appendChild(information);
|
||
|
|
||
|
// This "deprecation" node will contain info about deprecated usage.
|
||
|
deprecation = document.createElement('div');
|
||
|
deprecation.className = 'CodeMirror-hint-deprecation';
|
||
|
hintsUl.appendChild(deprecation);
|
||
|
|
||
|
// When CodeMirror attempts to remove the hint UI, we detect that it was
|
||
|
// removed and in turn remove the information nodes.
|
||
|
let onRemoveFn;
|
||
|
hintsUl.addEventListener(
|
||
|
'DOMNodeRemoved',
|
||
|
(onRemoveFn = (event) => {
|
||
|
if (event.target === hintsUl) {
|
||
|
hintsUl.removeEventListener('DOMNodeRemoved', onRemoveFn);
|
||
|
information = null;
|
||
|
deprecation = null;
|
||
|
onRemoveFn = null;
|
||
|
}
|
||
|
}),
|
||
|
);
|
||
|
}
|
||
|
|
||
|
// Now that the UI has been set up, add info to information.
|
||
|
const description = ctx.description
|
||
|
? md.render(ctx.description)
|
||
|
: 'Self descriptive.';
|
||
|
const type = ctx.type
|
||
|
? '<span class="infoType">' + renderType(ctx.type) + '</span>'
|
||
|
: '';
|
||
|
|
||
|
information.innerHTML =
|
||
|
'<div class="content">' +
|
||
|
(description.slice(0, 3) === '<p>'
|
||
|
? '<p>' + type + description.slice(3)
|
||
|
: type + description) +
|
||
|
'</div>';
|
||
|
|
||
|
if (ctx && deprecation && ctx.deprecationReason) {
|
||
|
const reason = ctx.deprecationReason
|
||
|
? md.render(ctx.deprecationReason)
|
||
|
: '';
|
||
|
deprecation.innerHTML =
|
||
|
'<span class="deprecation-label">Deprecated</span>' + reason;
|
||
|
deprecation.style.display = 'block';
|
||
|
} else if (deprecation) {
|
||
|
deprecation.style.display = 'none';
|
||
|
}
|
||
|
|
||
|
// Additional rendering?
|
||
|
if (onHintInformationRender) {
|
||
|
onHintInformationRender(information);
|
||
|
}
|
||
|
},
|
||
|
);
|
||
|
}
|
||
|
|
||
|
function renderType(type) {
|
||
|
if (type instanceof GraphQLNonNull) {
|
||
|
return `${renderType(type.ofType)}!`;
|
||
|
}
|
||
|
if (type instanceof GraphQLList) {
|
||
|
return `[${renderType(type.ofType)}]`;
|
||
|
}
|
||
|
return `<a class="typeName">${escapeHTML(type.name)}</a>`;
|
||
|
}
|