diff --git a/routers/web/repo/issue_view.go b/routers/web/repo/issue_view.go index af13a1156ed..852b880ab05 100644 --- a/routers/web/repo/issue_view.go +++ b/routers/web/repo/issue_view.go @@ -18,7 +18,6 @@ import ( "code.gitea.io/gitea/models/organization" access_model "code.gitea.io/gitea/models/perm/access" project_model "code.gitea.io/gitea/models/project" - pull_model "code.gitea.io/gitea/models/pull" "code.gitea.io/gitea/models/renderhelper" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" @@ -826,6 +825,7 @@ func (prInfo *pullRequestViewInfo) prepareMergeBox(ctx *context.Context, issue * panic("impossible, issue must be the same") } + pull := issue.PullRequest data := &pullMergeBoxData{} prInfo.MergeBoxData = data @@ -834,14 +834,12 @@ func (prInfo *pullRequestViewInfo) prepareMergeBox(ctx *context.Context, issue * statusCheckData = &pullCommitStatusCheckData{} // make the following logic easier, no need to keep checking "nil" } - pull := issue.PullRequest canDelete := false allowMerge := false canWriteToHeadRepo := false pull_service.StartPullRequestCheckOnView(ctx, pull) - ctx.Data["GetCommitMessages"] = "" if !prInfo.IsPullRequestBroken { var err error ctx.Data["UpdateAllowed"], ctx.Data["UpdateByRebaseAllowed"], err = pull_service.IsUserAllowedToUpdate(ctx, pull, ctx.Doer) @@ -849,7 +847,6 @@ func (prInfo *pullRequestViewInfo) prepareMergeBox(ctx *context.Context, issue * ctx.ServerError("IsUserAllowedToUpdate", err) return } - ctx.Data["GetCommitMessages"] = pull_service.GetSquashMergeCommitMessages(ctx, pull) } if pull.IsFilesConflicted() { @@ -903,59 +900,11 @@ func (prInfo *pullRequestViewInfo) prepareMergeBox(ctx *context.Context, issue * } } - data.ReloadingInterval = util.Iif(pull != nil && pull.IsChecking(), 2000, 0) - ctx.Data["CanWriteToHeadRepo"] = canWriteToHeadRepo - ctx.Data["ShowMergeInstructions"] = canWriteToHeadRepo + data.ReloadingInterval = util.Iif(pull.IsChecking(), 2000, 0) + data.ShowMergeInstructions = canWriteToHeadRepo + data.ShowPullCommands = pull.HeadRepo != nil && !pull.HasMerged && !issue.IsClosed ctx.Data["AllowMerge"] = allowMerge - prUnit, err := issue.Repo.GetUnit(ctx, unit.TypePullRequests) - if err != nil { - ctx.ServerError("GetUnit", err) - return - } - prConfig := prUnit.PullRequestsConfig() - - ctx.Data["AutodetectManualMerge"] = prConfig.AutodetectManualMerge - - var mergeStyle repo_model.MergeStyle - // Check correct values and select default - if ms, ok := ctx.Data["MergeStyle"].(repo_model.MergeStyle); !ok || - !prConfig.IsMergeStyleAllowed(ms) { - if prConfig.IsMergeStyleAllowed(prConfig.DefaultMergeStyle) && !ok { - mergeStyle = prConfig.DefaultMergeStyle - } else if prConfig.AllowMerge { - mergeStyle = repo_model.MergeStyleMerge - } else if prConfig.AllowRebase { - mergeStyle = repo_model.MergeStyleRebase - } else if prConfig.AllowRebaseMerge { - mergeStyle = repo_model.MergeStyleRebaseMerge - } else if prConfig.AllowSquash { - mergeStyle = repo_model.MergeStyleSquash - } else if prConfig.AllowFastForwardOnly { - mergeStyle = repo_model.MergeStyleFastForwardOnly - } else if prConfig.AllowManualMerge { - mergeStyle = repo_model.MergeStyleManuallyMerged - } - } - - ctx.Data["MergeStyle"] = mergeStyle - - defaultMergeMessage, defaultMergeBody, err := pull_service.GetDefaultMergeMessage(ctx, ctx.Repo.GitRepo, pull, mergeStyle) - if err != nil { - ctx.ServerError("GetDefaultMergeMessage", err) - return - } - ctx.Data["DefaultMergeMessage"] = defaultMergeMessage - ctx.Data["DefaultMergeBody"] = defaultMergeBody - - defaultSquashMergeMessage, defaultSquashMergeBody, err := pull_service.GetDefaultMergeMessage(ctx, ctx.Repo.GitRepo, pull, repo_model.MergeStyleSquash) - if err != nil { - ctx.ServerError("GetDefaultSquashMergeMessage", err) - return - } - ctx.Data["DefaultSquashMergeMessage"] = defaultSquashMergeMessage - ctx.Data["DefaultSquashMergeBody"] = defaultSquashMergeBody - pb := prInfo.ProtectedBranchRule if pb != nil { pb.Repo = pull.BaseRepo @@ -995,6 +944,9 @@ func (prInfo *pullRequestViewInfo) prepareMergeBox(ctx *context.Context, issue * return } + prConfig := issue.Repo.MustGetUnit(ctx, unit.TypePullRequests).PullRequestsConfig() + data.AutodetectManualMerge = prConfig.AutodetectManualMerge + stillCanManualMerge := func() bool { if pull.HasMerged || issue.IsClosed || !ctx.IsSigned { return false @@ -1007,13 +959,6 @@ func (prInfo *pullRequestViewInfo) prepareMergeBox(ctx *context.Context, issue * ctx.Data["StillCanManualMerge"] = stillCanManualMerge() - // Check if there is a pending pr merge - ctx.Data["HasPendingPullRequestMerge"], ctx.Data["PendingPullRequestMerge"], err = pull_model.GetScheduledMergeByPullID(ctx, pull.ID) - if err != nil { - ctx.ServerError("GetScheduledMergeByPullID", err) - return - } - enableStatusCheck := pb != nil && pb.EnableStatusCheck ctx.Data["EnableStatusCheck"] = enableStatusCheck @@ -1043,6 +988,7 @@ func (prInfo *pullRequestViewInfo) prepareMergeBox(ctx *context.Context, issue * (!data.requireSigned || data.willSign) // signing requirement is satisfied ctx.Data["PullMergeBoxData"] = prInfo.MergeBoxData + prInfo.prepareMergeBoxFormProps(ctx) } func prepareIssueViewContent(ctx *context.Context, issue *issues_model.Issue) { diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index c532cbba22d..7b31a26d6f1 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -164,12 +164,13 @@ func getPullInfo(ctx *context.Context) (issue *issues_model.Issue, ok bool) { func (prInfo *pullRequestViewInfo) setTemplateDataMergeTarget(ctx *context.Context) { pull := prInfo.issue.PullRequest if ctx.Repo.Owner.Name == pull.MustHeadUserName(ctx) { - ctx.Data["HeadTarget"] = pull.HeadBranch + prInfo.headTarget = pull.HeadBranch } else if pull.HeadRepo == nil { - ctx.Data["HeadTarget"] = ctx.Locale.Tr("repo.pull.deleted_branch", pull.HeadBranch) + prInfo.headTarget = ctx.Locale.TrString("repo.pull.deleted_branch", pull.HeadBranch) } else { - ctx.Data["HeadTarget"] = pull.MustHeadUserName(ctx) + "/" + pull.HeadRepo.Name + ":" + pull.HeadBranch + prInfo.headTarget = pull.MustHeadUserName(ctx) + "/" + pull.HeadRepo.Name + ":" + pull.HeadBranch } + ctx.Data["HeadTarget"] = prInfo.headTarget ctx.Data["BaseTarget"] = pull.BaseBranch headBranchLink := "" if pull.Flow == issues_model.PullRequestFlowGithub { @@ -268,6 +269,11 @@ type pullMergeBoxData struct { HasOverridableBlockers bool CanMergeNow bool + MergeFormProps map[string]any + ShowPullCommands bool + ShowMergeInstructions bool + AutodetectManualMerge bool + // don't expose unneeded fields to templates, need more refactoring changes hasStatusCheckBlocker bool isPullBranchDeletable bool @@ -289,6 +295,7 @@ type pullRequestViewInfo struct { IsPullRequestBroken bool HeadBranchCommitID string + headTarget string // for display purpose only CompareInfo git_service.CompareInfo ProtectedBranchRule *git_model.ProtectedBranch diff --git a/routers/web/repo/pull_merge_form.go b/routers/web/repo/pull_merge_form.go new file mode 100644 index 00000000000..b390fd69349 --- /dev/null +++ b/routers/web/repo/pull_merge_form.go @@ -0,0 +1,147 @@ +// Copyright 2026 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package repo + +import ( + "html/template" + + pull_model "code.gitea.io/gitea/models/pull" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unit" + "code.gitea.io/gitea/modules/templates" + "code.gitea.io/gitea/services/context" + pull_service "code.gitea.io/gitea/services/pull" +) + +func (prInfo *pullRequestViewInfo) prepareMergeBoxFormProps(ctx *context.Context) { + pull := prInfo.issue.PullRequest + prConfig := ctx.Repo.Repository.MustGetUnit(ctx, unit.TypePullRequests).PullRequestsConfig() + + // Check correct values and select default + var mergeStyle repo_model.MergeStyle + if prConfig.IsMergeStyleAllowed(prConfig.DefaultMergeStyle) { + mergeStyle = prConfig.DefaultMergeStyle + } else if prConfig.AllowMerge { + mergeStyle = repo_model.MergeStyleMerge + } else if prConfig.AllowRebase { + mergeStyle = repo_model.MergeStyleRebase + } else if prConfig.AllowRebaseMerge { + mergeStyle = repo_model.MergeStyleRebaseMerge + } else if prConfig.AllowSquash { + mergeStyle = repo_model.MergeStyleSquash + } else if prConfig.AllowFastForwardOnly { + mergeStyle = repo_model.MergeStyleFastForwardOnly + } else if prConfig.AllowManualMerge { + mergeStyle = repo_model.MergeStyleManuallyMerged + } + if mergeStyle == "" { + return + } + + // Check if there is a pending pr merge + hasPendingPullRequestMerge, pendingPullRequestMerge, err := pull_model.GetScheduledMergeByPullID(ctx, pull.ID) + if err != nil { + ctx.ServerError("GetScheduledMergeByPullID", err) + return + } + + var hasPendingPullRequestMergeTip template.HTML + if hasPendingPullRequestMerge { + createdPRMergeStr := templates.TimeSince(pendingPullRequestMerge.CreatedUnix) + hasPendingPullRequestMergeTip = ctx.Locale.Tr("repo.pulls.auto_merge_has_pending_schedule", pendingPullRequestMerge.Doer.Name, createdPRMergeStr) + } + + defaultMergeTitle, defaultMergeBody, err := pull_service.GetDefaultMergeMessage(ctx, ctx.Repo.GitRepo, pull, mergeStyle) + if err != nil { + ctx.ServerError("GetDefaultMergeMessage", err) + return + } + defaultSquashMergeTitle, defaultSquashMergeBody, err := pull_service.GetDefaultMergeMessage(ctx, ctx.Repo.GitRepo, pull, repo_model.MergeStyleSquash) + if err != nil { + ctx.ServerError("GetDefaultSquashMergeMessage", err) + return + } + + var defaultSquashMergeCommitMessages string + if !prInfo.IsPullRequestBroken { + defaultSquashMergeCommitMessages = pull_service.GetSquashMergeCommitMessages(ctx, pull) + } + + allOverridableChecksOk := !prInfo.MergeBoxData.HasOverridableBlockers + prInfo.MergeBoxData.MergeFormProps = map[string]any{ + "baseLink": prInfo.issue.Link(), + "textCancel": ctx.Locale.Tr("cancel"), + "textDeleteBranch": ctx.Locale.Tr("repo.branch.delete", prInfo.headTarget), + "textAutoMergeButtonWhenSucceed": ctx.Locale.Tr("repo.pulls.auto_merge_button_when_succeed"), + "textAutoMergeWhenSucceed": ctx.Locale.Tr("repo.pulls.auto_merge_when_succeed"), + "textAutoMergeCancelSchedule": ctx.Locale.Tr("repo.pulls.auto_merge_cancel_schedule"), + "textClearMergeMessage": ctx.Locale.Tr("repo.pulls.clear_merge_message"), + "textClearMergeMessageHint": ctx.Locale.Tr("repo.pulls.clear_merge_message_hint"), + "textMergeCommitId": ctx.Locale.Tr("repo.pulls.merge_commit_id"), + + "canMergeNow": prInfo.MergeBoxData.CanMergeNow, + "allOverridableChecksOk": allOverridableChecksOk, + "emptyCommit": pull.IsEmpty(), + "pullHeadCommitID": prInfo.CompareInfo.HeadCommitID, + "isPullBranchDeletable": prInfo.MergeBoxData.isPullBranchDeletable, + "defaultMergeStyle": mergeStyle, + "defaultDeleteBranchAfterMerge": prConfig.DefaultDeleteBranchAfterMerge, + "mergeMessageFieldPlaceHolder": ctx.Locale.Tr("repo.editor.commit_message_desc"), + "defaultMergeMessage": defaultMergeBody, + + "hasPendingPullRequestMerge": hasPendingPullRequestMerge, + "hasPendingPullRequestMergeTip": hasPendingPullRequestMergeTip, + } + + // if this pr can be merged now, then hide the auto merge + generalHideAutoMerge := prInfo.MergeBoxData.CanMergeNow && allOverridableChecksOk + + prInfo.MergeBoxData.MergeFormProps["mergeStyles"] = []any{ + map[string]any{ + "name": "merge", + "allowed": prConfig.AllowMerge, + "textDoMerge": ctx.Locale.Tr("repo.pulls.merge_pull_request"), + "mergeTitleFieldText": defaultMergeTitle, + "mergeMessageFieldText": defaultMergeBody, + "hideAutoMerge": generalHideAutoMerge, + }, + map[string]any{ + "name": "rebase", + "allowed": prConfig.AllowRebase, + "textDoMerge": ctx.Locale.Tr("repo.pulls.rebase_merge_pull_request"), + "hideMergeMessageTexts": true, + "hideAutoMerge": generalHideAutoMerge, + }, + map[string]any{ + "name": "rebase-merge", + "allowed": prConfig.AllowRebaseMerge, + "textDoMerge": ctx.Locale.Tr("repo.pulls.rebase_merge_commit_pull_request"), + "mergeTitleFieldText": defaultMergeTitle, + "mergeMessageFieldText": defaultMergeBody, + "hideAutoMerge": generalHideAutoMerge, + }, + map[string]any{ + "name": "squash", + "allowed": prConfig.AllowSquash, + "textDoMerge": ctx.Locale.Tr("repo.pulls.squash_merge_pull_request"), + "mergeTitleFieldText": defaultSquashMergeTitle, + "mergeMessageFieldText": defaultSquashMergeCommitMessages + defaultSquashMergeBody, + "hideAutoMerge": generalHideAutoMerge, + }, + map[string]any{ + "name": "fast-forward-only", + "allowed": prConfig.AllowFastForwardOnly && pull.CommitsBehind == 0, + "textDoMerge": ctx.Locale.Tr("repo.pulls.fast_forward_only_merge_pull_request"), + "hideMergeMessageTexts": true, + "hideAutoMerge": generalHideAutoMerge, + }, + map[string]any{ + "name": "manually-merged", + "allowed": prConfig.AllowManualMerge, + "textDoMerge": ctx.Locale.Tr("repo.pulls.merge_manually"), + "hideMergeMessageTexts": true, + "hideAutoMerge": true, + }, + } +} diff --git a/templates/repo/issue/view_content/pull_merge_box.tmpl b/templates/repo/issue/view_content/pull_merge_box.tmpl index 84d703debc5..768d3b31194 100644 --- a/templates/repo/issue/view_content/pull_merge_box.tmpl +++ b/templates/repo/issue/view_content/pull_merge_box.tmpl @@ -208,100 +208,11 @@ {{end}} {{if .AllowMerge}} {{/* user is allowed to merge */}} - {{$prUnit := .Repository.MustGetUnit ctx ctx.Consts.RepoUnitTypePullRequests}} - {{if or $prUnit.PullRequestsConfig.AllowMerge $prUnit.PullRequestsConfig.AllowRebase $prUnit.PullRequestsConfig.AllowRebaseMerge $prUnit.PullRequestsConfig.AllowSquash $prUnit.PullRequestsConfig.AllowFastForwardOnly}} - {{$hasPendingPullRequestMergeTip := ""}} - {{if .HasPendingPullRequestMerge}} - {{$createdPRMergeStr := DateUtils.TimeSince .PendingPullRequestMerge.CreatedUnix}} - {{$hasPendingPullRequestMergeTip = ctx.Locale.Tr "repo.pulls.auto_merge_has_pending_schedule" .PendingPullRequestMerge.Doer.Name $createdPRMergeStr}} - {{end}} + {{if $data.MergeFormProps}}
- - {{$showGeneralMergeForm = true}} {{/* The merge form is a Vue component. After mounted, it has a button for choosing merge style, so make it have min-height to avoid layout shifting */}} -
+
{{else}} {{/* no merge style was set in repo setting: not or ($prUnit.PullRequestsConfig.AllowMerge ...) */}}
@@ -396,8 +307,8 @@ {{end}} - {{if and .Issue.PullRequest.HeadRepo (not .Issue.PullRequest.HasMerged) (not .Issue.IsClosed)}} - {{template "repo/issue/view_content/pull_merge_instruction" dict "PullRequest" .Issue.PullRequest "ShowMergeInstructions" .ShowMergeInstructions}} + {{if $data.ShowPullCommands}} + {{template "repo/issue/view_content/pull_merge_instruction" dict "PullRequest" .Issue.PullRequest "MergeBoxData" $data}} {{end}} diff --git a/templates/repo/issue/view_content/pull_merge_instruction.tmpl b/templates/repo/issue/view_content/pull_merge_instruction.tmpl index b52333466d8..ad85c004505 100644 --- a/templates/repo/issue/view_content/pull_merge_instruction.tmpl +++ b/templates/repo/issue/view_content/pull_merge_instruction.tmpl @@ -1,57 +1,59 @@ +{{$data := $.MergeBoxData}} +{{$pull := $.PullRequest}}
{{ctx.Locale.Tr "repo.pulls.cmd_instruction_hint"}}

{{ctx.Locale.Tr "repo.pulls.cmd_instruction_checkout_title"}}

{{ctx.Locale.Tr "repo.pulls.cmd_instruction_checkout_desc"}}
- {{$localBranch := .PullRequest.HeadBranch}} - {{if ne .PullRequest.HeadRepo.ID .PullRequest.BaseRepo.ID}} - {{$localBranch = print .PullRequest.HeadRepo.OwnerName "-" .PullRequest.HeadBranch}} + {{$localBranch := $pull.HeadBranch}} + {{if ne $pull.HeadRepo.ID $pull.BaseRepo.ID}} + {{$localBranch = print $pull.HeadRepo.OwnerName "-" $pull.HeadBranch}} {{end}}
{{$gitRemoteName := ctx.RootData.SystemConfig.Repository.GitGuideRemoteName.Value ctx}} - {{if eq .PullRequest.Flow 0}} -
git fetch -u {{if ne .PullRequest.HeadRepo.ID .PullRequest.BaseRepo.ID}}{{ctx.AppFullLink .PullRequest.HeadRepo.Link}}{{else}}{{$gitRemoteName}}{{end}} {{.PullRequest.HeadBranch}}:{{$localBranch}}
+ {{if eq $pull.Flow 0}} +
git fetch -u {{if ne $pull.HeadRepo.ID $pull.BaseRepo.ID}}{{ctx.AppFullLink $pull.HeadRepo.Link}}{{else}}{{$gitRemoteName}}{{end}} {{$pull.HeadBranch}}:{{$localBranch}}
{{else}} -
git fetch -u {{$gitRemoteName}} {{.PullRequest.GetGitHeadRefName}}:{{$localBranch}}
+
git fetch -u {{$gitRemoteName}} {{$pull.GetGitHeadRefName}}:{{$localBranch}}
{{end}}
git checkout {{$localBranch}}
- {{if .ShowMergeInstructions}} + {{if $data.ShowMergeInstructions}}

{{ctx.Locale.Tr "repo.pulls.cmd_instruction_merge_title"}}

{{ctx.Locale.Tr "repo.pulls.cmd_instruction_merge_desc"}} - {{if not .AutodetectManualMerge}} + {{if not $data.AutodetectManualMerge}}
{{ctx.Locale.Tr "repo.pulls.cmd_instruction_merge_warning"}}
{{end}}
-
git checkout {{.PullRequest.BaseBranch}}
+
git checkout {{$pull.BaseBranch}}
git merge --no-ff {{$localBranch}}
-
git checkout {{.PullRequest.BaseBranch}}
+
git checkout {{$pull.BaseBranch}}
git merge --ff-only {{$localBranch}}
git checkout {{$localBranch}}
-
git rebase {{.PullRequest.BaseBranch}}
-
git checkout {{.PullRequest.BaseBranch}}
+
git rebase {{$pull.BaseBranch}}
+
git checkout {{$pull.BaseBranch}}
git merge --no-ff {{$localBranch}}
-
git checkout {{.PullRequest.BaseBranch}}
+
git checkout {{$pull.BaseBranch}}
git merge --squash {{$localBranch}}
-
git checkout {{.PullRequest.BaseBranch}}
+
git checkout {{$pull.BaseBranch}}
git merge --ff-only {{$localBranch}}
-
git checkout {{.PullRequest.BaseBranch}}
+
git checkout {{$pull.BaseBranch}}
git merge {{$localBranch}}
-
git push {{$gitRemoteName}} {{.PullRequest.BaseBranch}}
+
git push {{$gitRemoteName}} {{$pull.BaseBranch}}
{{end}}
diff --git a/web_src/js/components/PullRequestMergeForm.vue b/web_src/js/components/PullRequestMergeForm.vue index 7ae8fbfdaf7..d2835fe163d 100644 --- a/web_src/js/components/PullRequestMergeForm.vue +++ b/web_src/js/components/PullRequestMergeForm.vue @@ -3,9 +3,11 @@ import {computed, onMounted, onUnmounted, shallowRef, watch} from 'vue'; import {SvgIcon} from '../svg.ts'; import {toggleElem} from '../utils/dom.ts'; -const {pageData} = window.config; +const props = defineProps<{ + mergeFormProps: any, // TODO: this is a huge object, need to be refactored in the future +}>(); -const mergeForm = pageData.pullRequestMergeForm!; +const mergeForm = props.mergeFormProps; const mergeTitleFieldValue = shallowRef(''); const mergeMessageFieldValue = shallowRef(''); diff --git a/web_src/js/features/repo-issue-pull.ts b/web_src/js/features/repo-issue-pull.ts index 4e148b3ec0f..33e072a1a5e 100644 --- a/web_src/js/features/repo-issue-pull.ts +++ b/web_src/js/features/repo-issue-pull.ts @@ -63,27 +63,10 @@ async function initRepoPullRequestMergeForm(box: HTMLElement) { const el = box.querySelector('#pull-request-merge-form'); if (!el) return; + const data = JSON.parse(el.getAttribute('data-merge-form-props')!); const {default: PullRequestMergeForm} = await import('../components/PullRequestMergeForm.vue'); - const view = createApp(PullRequestMergeForm); - view.mount(el); -} - -function executeScripts(elem: Element) { - // find any existing nonce value from the current page and apply it to the new script - const scriptNonce = document.querySelector('script[nonce]')!.getAttribute('nonce')!; - for (const oldScript of elem.querySelectorAll('script')) { - // TODO: that's the only way to load the data for the merge form. In the future - // we need to completely decouple the page data and embedded script - // eslint-disable-next-line github/no-dynamic-script-tag - const newScript = document.createElement('script'); - for (const attr of oldScript.attributes) { - if (attr.name === 'type' && attr.value === 'module') continue; - newScript.setAttribute(attr.name, attr.value); - } - newScript.setAttribute('nonce', scriptNonce); - newScript.text = oldScript.text; - document.body.append(newScript); - } + const view = createApp(PullRequestMergeForm, {mergeFormProps: data}); + view.mount(el); // TODO: can unmount when reloaded? } export function initRepoPullMergeBox(el: HTMLElement) { @@ -124,7 +107,6 @@ export function initRepoPullMergeBox(el: HTMLElement) { } document.removeEventListener('visibilitychange', onVisibilityChange); const newElem = createElementFromHTML(await resp.text()); - executeScripts(newElem); el.replaceWith(newElem); };