Skip to content
Snippets Groups Projects

Resolve "When the branch name is a divider or separator, the project home page cannot display the branch name correctly."

2 unresolved threads
2 files
+ 181
111
Compare changes
  • Side-by-side
  • Inline
Files
2
  • 16ecdf2a
    Basic Intent: Allow all branch names without accidentally creating
    layout or backstage DOM. e.g. a branch named `separator` should never
    create a separator `li` element.  
    
    Ideally, there should never be a string that could cause this kind of 
    conflict.  
    
    Implementation: All of `GitLabDropdown.renderItem` is extracted to a 
    standalone module.  
    
    To render a divider or separator, consumers must now pass in an object 
    like `{ "type": "divider" }` or `{ "type": "separator" }`   
    
    Notable choices:  
    - All of the functions have a cyclomatic complexity of 3 or less
        - See: https://en.wikipedia.org/wiki/Cyclomatic_complexity
        - Note the "Correlation to number of defects" section
        - While software complexity may not have a directly causal
          relationship with defects, less complex software is generally
          easier to reason about, and **may** reduce defects.
          I personally try to maintain complexity of no higher than 3.
    - Everything other than the branch names fix matches past behavior 
    exactly
        - Including:
            - Unused variables
            - Class list order
+ 158
0
const renderersByType = {
divider(element) {
element.classList.add('divider');
return element;
},
separator(element) {
element.classList.add('separator');
return element;
},
header(element, data) {
element.classList.add('dropdown-header');
element.innerHTML = data.content;
return element;
},
};
function getPropertyWithDefault(data, options, property, defaultValue = '') {
let result;
if (options[property] != null) {
result = options[property](data);
} else {
result = data[property] != null ? data[property] : defaultValue;
}
return result;
}
function getHighlightTextBuilder(text, data, options) {
if (options.highlight) {
return data.template
? options.highlightTemplate(text, data.template)
: options.highlightText(text);
}
return text;
}
function getIconTextBuilder(text, data, options) {
if (options.icon) {
const wrappedText = `<span>${text}</span>`;
return data.icon ? `${data.icon}${wrappedText}` : wrappedText;
}
return text;
}
function getLinkText(data, options) {
const text = getPropertyWithDefault(data, options, 'text');
return [getHighlightTextBuilder, getIconTextBuilder].reduce(
(acc, fn) => fn(acc, data, options),
text,
);
}
function escape(text) {
return text ? String(text).replace(/'/g, "\\'") : text;
}
function getOptionValue(data, options) {
if (options.renderRow) {
return undefined;
}
return escape(options.id ? options.id(data) : data.id);
}
function shouldHide(data, { options }) {
const value = getOptionValue(data, options);
return options.hideRow && options.hideRow(value);
}
function hideElement(element) {
element.style.display = 'none';
return element;
}
function checkSelected(data, options) {
const value = getOptionValue(data, options);
if (!options.parent) {
return !data.id;
} else if (value) {
return (
options.parent.querySelector(`input[name='${options.fieldName}'][value='${value}']`) != null
);
}
return options.parent.querySelector(`input[name='${options.fieldName}']`) == null;
}
function createLink(url, selected, options) {
const link = document.createElement('a');
link.href = url;
if (options.icon) {
link.classList.add('d-flex', 'align-items-center');
}
link.classList.toggle('is-active', selected);
return link;
}
function assignTextToLink(el, data, options) {
const text = getLinkText(data, options);
if (options.icon || options.highlight) {
el.innerHTML = text;
} else {
el.textContent = text;
}
return el;
}
function renderLink(row, data, { options, group, index }) {
const selected = checkSelected(data, options);
const url = getPropertyWithDefault(data, options, 'url', '#');
const link = createLink(url, selected, options);
assignTextToLink(link, data, options);
if (group) {
link.dataset.group = group;
link.dataset.index = index;
}
row.appendChild(link);
return row;
}
function getOptionRenderer({ options, instance }) {
return options.renderRow && ((li, data) => options.renderRow(data, instance));
}
function getRenderer(data, params) {
return renderersByType[data.type] || getOptionRenderer(params) || renderLink;
}
export default function item({ data, ...params }) {
const renderer = getRenderer(data, params);
const li = document.createElement('li');
if (shouldHide(data, params)) {
hideElement(li);
}
return renderer(li, data, params);
}
Loading