mirror of
https://github.com/go-gitea/gitea.git
synced 2025-04-15 13:47:42 +00:00
Merge branch 'main' into fix/webhook/url
This commit is contained in:
commit
ef7fa304de
@ -8,17 +8,9 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
activities_model "code.gitea.io/gitea/models/activities"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
git_model "code.gitea.io/gitea/models/git"
|
||||
access_model "code.gitea.io/gitea/models/perm/access"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
issue_indexer "code.gitea.io/gitea/modules/indexer/issues"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
|
||||
const notRegularFileMode = os.ModeSymlink | os.ModeNamedPipe | os.ModeSocket | os.ModeDevice | os.ModeCharDevice | os.ModeIrregular
|
||||
@ -63,97 +55,3 @@ func UpdateRepoSize(ctx context.Context, repo *repo_model.Repository) error {
|
||||
|
||||
return repo_model.UpdateRepoSize(ctx, repo.ID, size, lfsSize)
|
||||
}
|
||||
|
||||
// CheckDaemonExportOK creates/removes git-daemon-export-ok for git-daemon...
|
||||
func CheckDaemonExportOK(ctx context.Context, repo *repo_model.Repository) error {
|
||||
if err := repo.LoadOwner(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create/Remove git-daemon-export-ok for git-daemon...
|
||||
daemonExportFile := filepath.Join(repo.RepoPath(), `git-daemon-export-ok`)
|
||||
|
||||
isExist, err := util.IsExist(daemonExportFile)
|
||||
if err != nil {
|
||||
log.Error("Unable to check if %s exists. Error: %v", daemonExportFile, err)
|
||||
return err
|
||||
}
|
||||
|
||||
isPublic := !repo.IsPrivate && repo.Owner.Visibility == api.VisibleTypePublic
|
||||
if !isPublic && isExist {
|
||||
if err = util.Remove(daemonExportFile); err != nil {
|
||||
log.Error("Failed to remove %s: %v", daemonExportFile, err)
|
||||
}
|
||||
} else if isPublic && !isExist {
|
||||
if f, err := os.Create(daemonExportFile); err != nil {
|
||||
log.Error("Failed to create %s: %v", daemonExportFile, err)
|
||||
} else {
|
||||
f.Close()
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateRepository updates a repository with db context
|
||||
func UpdateRepository(ctx context.Context, repo *repo_model.Repository, visibilityChanged bool) (err error) {
|
||||
repo.LowerName = strings.ToLower(repo.Name)
|
||||
|
||||
e := db.GetEngine(ctx)
|
||||
|
||||
if _, err = e.ID(repo.ID).AllCols().Update(repo); err != nil {
|
||||
return fmt.Errorf("update: %w", err)
|
||||
}
|
||||
|
||||
if err = UpdateRepoSize(ctx, repo); err != nil {
|
||||
log.Error("Failed to update size for repository: %v", err)
|
||||
}
|
||||
|
||||
if visibilityChanged {
|
||||
if err = repo.LoadOwner(ctx); err != nil {
|
||||
return fmt.Errorf("LoadOwner: %w", err)
|
||||
}
|
||||
if repo.Owner.IsOrganization() {
|
||||
// Organization repository need to recalculate access table when visibility is changed.
|
||||
if err = access_model.RecalculateTeamAccesses(ctx, repo, 0); err != nil {
|
||||
return fmt.Errorf("recalculateTeamAccesses: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// If repo has become private, we need to set its actions to private.
|
||||
if repo.IsPrivate {
|
||||
_, err = e.Where("repo_id = ?", repo.ID).Cols("is_private").Update(&activities_model.Action{
|
||||
IsPrivate: true,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = repo_model.ClearRepoStars(ctx, repo.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Create/Remove git-daemon-export-ok for git-daemon...
|
||||
if err := CheckDaemonExportOK(ctx, repo); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
forkRepos, err := repo_model.GetRepositoriesByForkID(ctx, repo.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("getRepositoriesByForkID: %w", err)
|
||||
}
|
||||
for i := range forkRepos {
|
||||
forkRepos[i].IsPrivate = repo.IsPrivate || repo.Owner.Visibility == api.VisibleTypePrivate
|
||||
if err = UpdateRepository(ctx, forkRepos[i], true); err != nil {
|
||||
return fmt.Errorf("updateRepository[%d]: %w", forkRepos[i].ID, err)
|
||||
}
|
||||
}
|
||||
|
||||
// If visibility is changed, we need to update the issue indexer.
|
||||
// Since the data in the issue indexer have field to indicate if the repo is public or not.
|
||||
issue_indexer.UpdateRepoIndexer(ctx, repo.ID)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ package repository
|
||||
import (
|
||||
"testing"
|
||||
|
||||
activities_model "code.gitea.io/gitea/models/activities"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
@ -14,26 +13,6 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestUpdateRepositoryVisibilityChanged(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
// Get sample repo and change visibility
|
||||
repo, err := repo_model.GetRepositoryByID(db.DefaultContext, 9)
|
||||
assert.NoError(t, err)
|
||||
repo.IsPrivate = true
|
||||
|
||||
// Update it
|
||||
err = UpdateRepository(db.DefaultContext, repo, true)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Check visibility of action has become private
|
||||
act := activities_model.Action{}
|
||||
_, err = db.GetEngine(db.DefaultContext).ID(3).Get(&act)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, act.IsPrivate)
|
||||
}
|
||||
|
||||
func TestGetDirectorySize(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
repo, err := repo_model.GetRepositoryByID(db.DefaultContext, 1)
|
||||
|
@ -196,7 +196,7 @@ func adoptRepository(ctx context.Context, repo *repo_model.Repository, defaultBr
|
||||
return fmt.Errorf("setDefaultBranch: %w", err)
|
||||
}
|
||||
}
|
||||
if err = repo_module.UpdateRepository(ctx, repo, false); err != nil {
|
||||
if err = updateRepository(ctx, repo, false); err != nil {
|
||||
return fmt.Errorf("updateRepository: %w", err)
|
||||
}
|
||||
|
||||
|
@ -464,7 +464,7 @@ func cleanupRepository(doer *user_model.User, repoID int64) {
|
||||
}
|
||||
|
||||
func updateGitRepoAfterCreate(ctx context.Context, repo *repo_model.Repository) error {
|
||||
if err := repo_module.CheckDaemonExportOK(ctx, repo); err != nil {
|
||||
if err := checkDaemonExportOK(ctx, repo); err != nil {
|
||||
return fmt.Errorf("checkDaemonExportOK: %w", err)
|
||||
}
|
||||
|
||||
|
@ -227,7 +227,7 @@ func ConvertForkToNormalRepository(ctx context.Context, repo *repo_model.Reposit
|
||||
repo.IsFork = false
|
||||
repo.ForkID = 0
|
||||
|
||||
if err := repo_module.UpdateRepository(ctx, repo, false); err != nil {
|
||||
if err := updateRepository(ctx, repo, false); err != nil {
|
||||
log.Error("Unable to update repository %-v whilst converting from fork. Error: %v", repo, err)
|
||||
return err
|
||||
}
|
||||
|
@ -7,20 +7,27 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
activities_model "code.gitea.io/gitea/models/activities"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/git"
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
"code.gitea.io/gitea/models/organization"
|
||||
access_model "code.gitea.io/gitea/models/perm/access"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unit"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/graceful"
|
||||
issue_indexer "code.gitea.io/gitea/modules/indexer/issues"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/queue"
|
||||
repo_module "code.gitea.io/gitea/modules/repository"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
notify_service "code.gitea.io/gitea/services/notify"
|
||||
pull_service "code.gitea.io/gitea/services/pull"
|
||||
)
|
||||
@ -109,42 +116,32 @@ func Init(ctx context.Context) error {
|
||||
|
||||
// UpdateRepository updates a repository
|
||||
func UpdateRepository(ctx context.Context, repo *repo_model.Repository, visibilityChanged bool) (err error) {
|
||||
ctx, committer, err := db.TxContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer committer.Close()
|
||||
|
||||
if err = repo_module.UpdateRepository(ctx, repo, visibilityChanged); err != nil {
|
||||
return fmt.Errorf("updateRepository: %w", err)
|
||||
}
|
||||
|
||||
return committer.Commit()
|
||||
}
|
||||
|
||||
func UpdateRepositoryVisibility(ctx context.Context, repo *repo_model.Repository, isPrivate bool) (err error) {
|
||||
ctx, committer, err := db.TxContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer committer.Close()
|
||||
|
||||
repo.IsPrivate = isPrivate
|
||||
|
||||
if err = repo_module.UpdateRepository(ctx, repo, true); err != nil {
|
||||
return fmt.Errorf("UpdateRepositoryVisibility: %w", err)
|
||||
}
|
||||
|
||||
return committer.Commit()
|
||||
return db.WithTx(ctx, func(ctx context.Context) error {
|
||||
if err = updateRepository(ctx, repo, visibilityChanged); err != nil {
|
||||
return fmt.Errorf("updateRepository: %w", err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func MakeRepoPublic(ctx context.Context, repo *repo_model.Repository) (err error) {
|
||||
return UpdateRepositoryVisibility(ctx, repo, false)
|
||||
return db.WithTx(ctx, func(ctx context.Context) error {
|
||||
repo.IsPrivate = false
|
||||
if err = updateRepository(ctx, repo, true); err != nil {
|
||||
return fmt.Errorf("MakeRepoPublic: %w", err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func MakeRepoPrivate(ctx context.Context, repo *repo_model.Repository) (err error) {
|
||||
return UpdateRepositoryVisibility(ctx, repo, true)
|
||||
return db.WithTx(ctx, func(ctx context.Context) error {
|
||||
repo.IsPrivate = true
|
||||
if err = updateRepository(ctx, repo, true); err != nil {
|
||||
return fmt.Errorf("MakeRepoPrivate: %w", err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// LinkedRepository returns the linked repo if any
|
||||
@ -170,3 +167,97 @@ func LinkedRepository(ctx context.Context, a *repo_model.Attachment) (*repo_mode
|
||||
}
|
||||
return nil, -1, nil
|
||||
}
|
||||
|
||||
// checkDaemonExportOK creates/removes git-daemon-export-ok for git-daemon...
|
||||
func checkDaemonExportOK(ctx context.Context, repo *repo_model.Repository) error {
|
||||
if err := repo.LoadOwner(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create/Remove git-daemon-export-ok for git-daemon...
|
||||
daemonExportFile := filepath.Join(repo.RepoPath(), `git-daemon-export-ok`)
|
||||
|
||||
isExist, err := util.IsExist(daemonExportFile)
|
||||
if err != nil {
|
||||
log.Error("Unable to check if %s exists. Error: %v", daemonExportFile, err)
|
||||
return err
|
||||
}
|
||||
|
||||
isPublic := !repo.IsPrivate && repo.Owner.Visibility == structs.VisibleTypePublic
|
||||
if !isPublic && isExist {
|
||||
if err = util.Remove(daemonExportFile); err != nil {
|
||||
log.Error("Failed to remove %s: %v", daemonExportFile, err)
|
||||
}
|
||||
} else if isPublic && !isExist {
|
||||
if f, err := os.Create(daemonExportFile); err != nil {
|
||||
log.Error("Failed to create %s: %v", daemonExportFile, err)
|
||||
} else {
|
||||
f.Close()
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// updateRepository updates a repository with db context
|
||||
func updateRepository(ctx context.Context, repo *repo_model.Repository, visibilityChanged bool) (err error) {
|
||||
repo.LowerName = strings.ToLower(repo.Name)
|
||||
|
||||
e := db.GetEngine(ctx)
|
||||
|
||||
if _, err = e.ID(repo.ID).AllCols().Update(repo); err != nil {
|
||||
return fmt.Errorf("update: %w", err)
|
||||
}
|
||||
|
||||
if err = repo_module.UpdateRepoSize(ctx, repo); err != nil {
|
||||
log.Error("Failed to update size for repository: %v", err)
|
||||
}
|
||||
|
||||
if visibilityChanged {
|
||||
if err = repo.LoadOwner(ctx); err != nil {
|
||||
return fmt.Errorf("LoadOwner: %w", err)
|
||||
}
|
||||
if repo.Owner.IsOrganization() {
|
||||
// Organization repository need to recalculate access table when visibility is changed.
|
||||
if err = access_model.RecalculateTeamAccesses(ctx, repo, 0); err != nil {
|
||||
return fmt.Errorf("recalculateTeamAccesses: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// If repo has become private, we need to set its actions to private.
|
||||
if repo.IsPrivate {
|
||||
_, err = e.Where("repo_id = ?", repo.ID).Cols("is_private").Update(&activities_model.Action{
|
||||
IsPrivate: true,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = repo_model.ClearRepoStars(ctx, repo.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Create/Remove git-daemon-export-ok for git-daemon...
|
||||
if err := checkDaemonExportOK(ctx, repo); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
forkRepos, err := repo_model.GetRepositoriesByForkID(ctx, repo.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("getRepositoriesByForkID: %w", err)
|
||||
}
|
||||
for i := range forkRepos {
|
||||
forkRepos[i].IsPrivate = repo.IsPrivate || repo.Owner.Visibility == structs.VisibleTypePrivate
|
||||
if err = updateRepository(ctx, forkRepos[i], true); err != nil {
|
||||
return fmt.Errorf("updateRepository[%d]: %w", forkRepos[i].ID, err)
|
||||
}
|
||||
}
|
||||
|
||||
// If visibility is changed, we need to update the issue indexer.
|
||||
// Since the data in the issue indexer have field to indicate if the repo is public or not.
|
||||
issue_indexer.UpdateRepoIndexer(ctx, repo.ID)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ package repository
|
||||
import (
|
||||
"testing"
|
||||
|
||||
activities_model "code.gitea.io/gitea/models/activities"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unit"
|
||||
@ -40,3 +41,23 @@ func TestLinkedRepository(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateRepositoryVisibilityChanged(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
// Get sample repo and change visibility
|
||||
repo, err := repo_model.GetRepositoryByID(db.DefaultContext, 9)
|
||||
assert.NoError(t, err)
|
||||
repo.IsPrivate = true
|
||||
|
||||
// Update it
|
||||
err = updateRepository(db.DefaultContext, repo, true)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Check visibility of action has become private
|
||||
act := activities_model.Action{}
|
||||
_, err = db.GetEngine(db.DefaultContext).ID(3).Get(&act)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, act.IsPrivate)
|
||||
}
|
||||
|
@ -747,6 +747,14 @@ overflow-menu .overflow-menu-button {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* match the styles of ".ui.secondary.pointing.menu .active.item" */
|
||||
overflow-menu.ui.secondary.pointing.menu .overflow-menu-button.active {
|
||||
padding: 2px 0 0;
|
||||
border-bottom: 2px solid currentcolor;
|
||||
background-color: transparent;
|
||||
font-weight: var(--font-weight-medium);
|
||||
}
|
||||
|
||||
overflow-menu .overflow-menu-button:hover {
|
||||
color: var(--color-text-dark);
|
||||
}
|
||||
|
@ -360,7 +360,7 @@ export function querySingleVisibleElem<T extends HTMLElement>(parent: Element, s
|
||||
export function addDelegatedEventListener<T extends HTMLElement, E extends Event>(parent: Node, type: string, selector: string, listener: (elem: T, e: E) => Promisable<void>, options?: boolean | AddEventListenerOptions) {
|
||||
parent.addEventListener(type, (e: Event) => {
|
||||
const elem = (e.target as HTMLElement).closest(selector);
|
||||
if (!elem) return;
|
||||
if (!elem || !parent.contains(elem)) return;
|
||||
listener(elem as T, e as E);
|
||||
}, options);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import {throttle} from 'throttle-debounce';
|
||||
import {createTippy} from '../modules/tippy.ts';
|
||||
import {isDocumentFragmentOrElementNode} from '../utils/dom.ts';
|
||||
import {addDelegatedEventListener, isDocumentFragmentOrElementNode} from '../utils/dom.ts';
|
||||
import octiconKebabHorizontal from '../../../public/assets/img/svg/octicon-kebab-horizontal.svg';
|
||||
|
||||
window.customElements.define('overflow-menu', class extends HTMLElement {
|
||||
@ -12,10 +12,14 @@ window.customElements.define('overflow-menu', class extends HTMLElement {
|
||||
mutationObserver: MutationObserver;
|
||||
lastWidth: number;
|
||||
|
||||
updateButtonActivationState() {
|
||||
if (!this.button || !this.tippyContent) return;
|
||||
this.button.classList.toggle('active', Boolean(this.tippyContent.querySelector('.item.active')));
|
||||
}
|
||||
|
||||
updateItems = throttle(100, () => {
|
||||
if (!this.tippyContent) {
|
||||
const div = document.createElement('div');
|
||||
div.classList.add('tippy-target');
|
||||
div.tabIndex = -1; // for initial focus, programmatic focus only
|
||||
div.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Tab') {
|
||||
@ -64,9 +68,10 @@ window.customElements.define('overflow-menu', class extends HTMLElement {
|
||||
}
|
||||
}
|
||||
});
|
||||
this.append(div);
|
||||
div.classList.add('tippy-target');
|
||||
this.handleItemClick(div, '.tippy-target > .item');
|
||||
this.tippyContent = div;
|
||||
}
|
||||
} // end if: no tippyContent and create a new one
|
||||
|
||||
const itemFlexSpace = this.menuItemsEl.querySelector<HTMLSpanElement>('.item-flex-space');
|
||||
const itemOverFlowMenuButton = this.querySelector<HTMLButtonElement>('.overflow-menu-button');
|
||||
@ -88,7 +93,7 @@ window.customElements.define('overflow-menu', class extends HTMLElement {
|
||||
const menuRight = this.offsetLeft + this.offsetWidth;
|
||||
const menuItems = this.menuItemsEl.querySelectorAll<HTMLElement>('.item, .item-flex-space');
|
||||
let afterFlexSpace = false;
|
||||
for (const item of menuItems) {
|
||||
for (const [idx, item] of menuItems.entries()) {
|
||||
if (item.classList.contains('item-flex-space')) {
|
||||
afterFlexSpace = true;
|
||||
continue;
|
||||
@ -96,7 +101,10 @@ window.customElements.define('overflow-menu', class extends HTMLElement {
|
||||
if (afterFlexSpace) item.setAttribute('data-after-flex-space', 'true');
|
||||
const itemRight = item.offsetLeft + item.offsetWidth;
|
||||
if (menuRight - itemRight < 38) { // roughly the width of .overflow-menu-button with some extra space
|
||||
this.tippyItems.push(item);
|
||||
const onlyLastItem = idx === menuItems.length - 1 && this.tippyItems.length === 0;
|
||||
const lastItemFit = onlyLastItem && menuRight - itemRight > 0;
|
||||
const moveToPopup = !onlyLastItem || !lastItemFit;
|
||||
if (moveToPopup) this.tippyItems.push(item);
|
||||
}
|
||||
}
|
||||
itemFlexSpace?.style.removeProperty('display');
|
||||
@ -107,6 +115,7 @@ window.customElements.define('overflow-menu', class extends HTMLElement {
|
||||
const btn = this.querySelector('.overflow-menu-button');
|
||||
btn?._tippy?.destroy();
|
||||
btn?.remove();
|
||||
this.button = null;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -126,18 +135,17 @@ window.customElements.define('overflow-menu', class extends HTMLElement {
|
||||
// update existing tippy
|
||||
if (this.button?._tippy) {
|
||||
this.button._tippy.setContent(this.tippyContent);
|
||||
this.updateButtonActivationState();
|
||||
return;
|
||||
}
|
||||
|
||||
// create button initially
|
||||
const btn = document.createElement('button');
|
||||
btn.classList.add('overflow-menu-button');
|
||||
btn.setAttribute('aria-label', window.config.i18n.more_items);
|
||||
btn.innerHTML = octiconKebabHorizontal;
|
||||
this.append(btn);
|
||||
this.button = btn;
|
||||
|
||||
createTippy(btn, {
|
||||
this.button = document.createElement('button');
|
||||
this.button.classList.add('overflow-menu-button');
|
||||
this.button.setAttribute('aria-label', window.config.i18n.more_items);
|
||||
this.button.innerHTML = octiconKebabHorizontal;
|
||||
this.append(this.button);
|
||||
createTippy(this.button, {
|
||||
trigger: 'click',
|
||||
hideOnClick: true,
|
||||
interactive: true,
|
||||
@ -151,6 +159,7 @@ window.customElements.define('overflow-menu', class extends HTMLElement {
|
||||
}, 0);
|
||||
},
|
||||
});
|
||||
this.updateButtonActivationState();
|
||||
});
|
||||
|
||||
init() {
|
||||
@ -187,6 +196,14 @@ window.customElements.define('overflow-menu', class extends HTMLElement {
|
||||
}
|
||||
});
|
||||
this.resizeObserver.observe(this);
|
||||
this.handleItemClick(this, '.overflow-menu-items > .item');
|
||||
}
|
||||
|
||||
handleItemClick(el: Element, selector: string) {
|
||||
addDelegatedEventListener(el, 'click', selector, () => {
|
||||
this.button?._tippy?.hide();
|
||||
this.updateButtonActivationState();
|
||||
});
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
|
Loading…
Reference in New Issue
Block a user