Merge pull request '[v1.22/gitea] week 15 cherry pick to v7.0' (#3113) from earl-warren/forgejo:wip-v7.0-gitea-cherry-pick into v7.0/forgejo
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/3113 Reviewed-by: Gusted <gusted@noreply.codeberg.org>
This commit is contained in:
commit
666432d15b
41 changed files with 373 additions and 1755 deletions
|
@ -134,3 +134,13 @@ func extractSignature(s string) (*packet.Signature, error) {
|
|||
}
|
||||
return sig, nil
|
||||
}
|
||||
|
||||
func tryGetKeyIDFromSignature(sig *packet.Signature) string {
|
||||
if sig.IssuerKeyId != nil && (*sig.IssuerKeyId) != 0 {
|
||||
return fmt.Sprintf("%016X", *sig.IssuerKeyId)
|
||||
}
|
||||
if sig.IssuerFingerprint != nil && len(sig.IssuerFingerprint) > 0 {
|
||||
return fmt.Sprintf("%016X", sig.IssuerFingerprint[12:20])
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
|
|
@ -123,13 +123,7 @@ func ParseObjectWithSignature(ctx context.Context, c *GitObject) *ObjectVerifica
|
|||
}
|
||||
}
|
||||
|
||||
keyID := ""
|
||||
if sig.IssuerKeyId != nil && (*sig.IssuerKeyId) != 0 {
|
||||
keyID = fmt.Sprintf("%X", *sig.IssuerKeyId)
|
||||
}
|
||||
if keyID == "" && sig.IssuerFingerprint != nil && len(sig.IssuerFingerprint) > 0 {
|
||||
keyID = fmt.Sprintf("%X", sig.IssuerFingerprint[12:20])
|
||||
}
|
||||
keyID := tryGetKeyIDFromSignature(sig)
|
||||
defaultReason := NoKeyFound
|
||||
|
||||
// First check if the sig has a keyID and if so just look at that
|
||||
|
|
|
@ -11,7 +11,9 @@ import (
|
|||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"github.com/keybase/go-crypto/openpgp/packet"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
@ -391,3 +393,13 @@ epiDVQ==
|
|||
assert.Equal(t, time.Unix(1586105389, 0), expire)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTryGetKeyIDFromSignature(t *testing.T) {
|
||||
assert.Empty(t, tryGetKeyIDFromSignature(&packet.Signature{}))
|
||||
assert.Equal(t, "038D1A3EADDBEA9C", tryGetKeyIDFromSignature(&packet.Signature{
|
||||
IssuerKeyId: util.ToPointer(uint64(0x38D1A3EADDBEA9C)),
|
||||
}))
|
||||
assert.Equal(t, "038D1A3EADDBEA9C", tryGetKeyIDFromSignature(&packet.Signature{
|
||||
IssuerFingerprint: []uint8{0xb, 0x23, 0x24, 0xc7, 0xe6, 0xfe, 0x4f, 0x3a, 0x6, 0x26, 0xc1, 0x21, 0x3, 0x8d, 0x1a, 0x3e, 0xad, 0xdb, 0xea, 0x9c},
|
||||
}))
|
||||
}
|
||||
|
|
|
@ -46,6 +46,10 @@ func VerifyGPGKey(ctx context.Context, ownerID int64, keyID, token, signature st
|
|||
return "", ErrGPGKeyNotExist{}
|
||||
}
|
||||
|
||||
if err := key.LoadSubKeys(ctx); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
sig, err := extractSignature(signature)
|
||||
if err != nil {
|
||||
return "", ErrGPGInvalidTokenSignature{
|
||||
|
|
|
@ -47,6 +47,12 @@ func convertPGPSignature(c *object.Commit) *ObjectSignature {
|
|||
return nil
|
||||
}
|
||||
|
||||
if c.Encoding != "" && c.Encoding != "UTF-8" {
|
||||
if _, err = fmt.Fprintf(&w, "\nencoding %s\n", c.Encoding); err != nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if _, err = fmt.Fprintf(&w, "\n\n%s", c.Message); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -84,6 +84,8 @@ readLoop:
|
|||
commit.Committer = &Signature{}
|
||||
commit.Committer.Decode(data)
|
||||
_, _ = payloadSB.Write(line)
|
||||
case "encoding":
|
||||
_, _ = payloadSB.Write(line)
|
||||
case "gpgsig":
|
||||
fallthrough
|
||||
case "gpgsig-sha256": // FIXME: no intertop, so only 1 exists at present.
|
||||
|
|
|
@ -125,6 +125,73 @@ empty commit`, commitFromReader.Signature.Payload)
|
|||
assert.EqualValues(t, commitFromReader, commitFromReader2)
|
||||
}
|
||||
|
||||
func TestCommitWithEncodingFromReader(t *testing.T) {
|
||||
commitString := `feaf4ba6bc635fec442f46ddd4512416ec43c2c2 commit 1074
|
||||
tree ca3fad42080dd1a6d291b75acdfc46e5b9b307e5
|
||||
parent 47b24e7ab977ed31c5a39989d570847d6d0052af
|
||||
author KN4CK3R <admin@oldschoolhack.me> 1711702962 +0100
|
||||
committer KN4CK3R <admin@oldschoolhack.me> 1711702962 +0100
|
||||
encoding ISO-8859-1
|
||||
gpgsig -----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQGzBAABCgAdFiEE9HRrbqvYxPT8PXbefPSEkrowAa8FAmYGg7IACgkQfPSEkrow
|
||||
Aa9olwv+P0HhtCM6CRvlUmPaqswRsDPNR4i66xyXGiSxdI9V5oJL7HLiQIM7KrFR
|
||||
gizKa2COiGtugv8fE+TKqXKaJx6uJUJEjaBd8E9Af9PrAzjWj+A84lU6/PgPS8hq
|
||||
zOfZraLOEWRH4tZcS+u2yFLu3ez2Wqh1xW5LNy7xqEedMXEFD1HwSJ0+pjacNkzr
|
||||
frp6Asyt7xRI6YmgFJZJoRsS3Ktr6rtKeRL2IErSQQyorOqj6gKrglhrhfG/114j
|
||||
FKB1v4or0WZ1DE8iP2SJZ3n+/K1IuWAINh7MVdb7PndfBPEa+IL+ucNk5uzEE8Jd
|
||||
G8smGxXUeFEt2cP1dj2W8EgAxuA9sTnH9dqI5aRqy5ifDjuya7Emm8sdOUvtGdmn
|
||||
SONRzusmu5n3DgV956REL7x62h7JuqmBz/12HZkr0z0zgXkcZ04q08pSJATX5N1F
|
||||
yN+tWxTsWg+zhDk96d5Esdo9JMjcFvPv0eioo30GAERaz1hoD7zCMT4jgUFTQwgz
|
||||
jw4YcO5u
|
||||
=r3UU
|
||||
-----END PGP SIGNATURE-----
|
||||
|
||||
ISO-8859-1`
|
||||
|
||||
sha := &Sha1Hash{0xfe, 0xaf, 0x4b, 0xa6, 0xbc, 0x63, 0x5f, 0xec, 0x44, 0x2f, 0x46, 0xdd, 0xd4, 0x51, 0x24, 0x16, 0xec, 0x43, 0xc2, 0xc2}
|
||||
gitRepo, err := openRepositoryWithDefaultContext(filepath.Join(testReposDir, "repo1_bare"))
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, gitRepo)
|
||||
defer gitRepo.Close()
|
||||
|
||||
commitFromReader, err := CommitFromReader(gitRepo, sha, strings.NewReader(commitString))
|
||||
assert.NoError(t, err)
|
||||
if !assert.NotNil(t, commitFromReader) {
|
||||
return
|
||||
}
|
||||
assert.EqualValues(t, sha, commitFromReader.ID)
|
||||
assert.EqualValues(t, `-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQGzBAABCgAdFiEE9HRrbqvYxPT8PXbefPSEkrowAa8FAmYGg7IACgkQfPSEkrow
|
||||
Aa9olwv+P0HhtCM6CRvlUmPaqswRsDPNR4i66xyXGiSxdI9V5oJL7HLiQIM7KrFR
|
||||
gizKa2COiGtugv8fE+TKqXKaJx6uJUJEjaBd8E9Af9PrAzjWj+A84lU6/PgPS8hq
|
||||
zOfZraLOEWRH4tZcS+u2yFLu3ez2Wqh1xW5LNy7xqEedMXEFD1HwSJ0+pjacNkzr
|
||||
frp6Asyt7xRI6YmgFJZJoRsS3Ktr6rtKeRL2IErSQQyorOqj6gKrglhrhfG/114j
|
||||
FKB1v4or0WZ1DE8iP2SJZ3n+/K1IuWAINh7MVdb7PndfBPEa+IL+ucNk5uzEE8Jd
|
||||
G8smGxXUeFEt2cP1dj2W8EgAxuA9sTnH9dqI5aRqy5ifDjuya7Emm8sdOUvtGdmn
|
||||
SONRzusmu5n3DgV956REL7x62h7JuqmBz/12HZkr0z0zgXkcZ04q08pSJATX5N1F
|
||||
yN+tWxTsWg+zhDk96d5Esdo9JMjcFvPv0eioo30GAERaz1hoD7zCMT4jgUFTQwgz
|
||||
jw4YcO5u
|
||||
=r3UU
|
||||
-----END PGP SIGNATURE-----
|
||||
`, commitFromReader.Signature.Signature)
|
||||
assert.EqualValues(t, `tree ca3fad42080dd1a6d291b75acdfc46e5b9b307e5
|
||||
parent 47b24e7ab977ed31c5a39989d570847d6d0052af
|
||||
author KN4CK3R <admin@oldschoolhack.me> 1711702962 +0100
|
||||
committer KN4CK3R <admin@oldschoolhack.me> 1711702962 +0100
|
||||
encoding ISO-8859-1
|
||||
|
||||
ISO-8859-1`, commitFromReader.Signature.Payload)
|
||||
assert.EqualValues(t, "KN4CK3R <admin@oldschoolhack.me>", commitFromReader.Author.String())
|
||||
|
||||
commitFromReader2, err := CommitFromReader(gitRepo, sha, strings.NewReader(commitString+"\n\n"))
|
||||
assert.NoError(t, err)
|
||||
commitFromReader.CommitMessage += "\n\n"
|
||||
commitFromReader.Signature.Payload += "\n\n"
|
||||
assert.EqualValues(t, commitFromReader, commitFromReader2)
|
||||
}
|
||||
|
||||
func TestHasPreviousCommit(t *testing.T) {
|
||||
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare")
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ func (c *FilesystemClient) Download(ctx context.Context, objects []Pointer, call
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer f.Close()
|
||||
if err := callback(p, f, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ func (c *FilesystemClient) Upload(ctx context.Context, objects []Pointer, callba
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer f.Close()
|
||||
_, err = io.Copy(f, content)
|
||||
|
||||
return err
|
||||
|
|
|
@ -505,9 +505,17 @@ func TestMathBlock(t *testing.T) {
|
|||
`\(a\) \(b\)`,
|
||||
`<p><code class="language-math is-loading">a</code> <code class="language-math is-loading">b</code></p>` + nl,
|
||||
},
|
||||
{
|
||||
`$a$.`,
|
||||
`<p><code class="language-math is-loading">a</code>.</p>` + nl,
|
||||
},
|
||||
{
|
||||
`.$a$`,
|
||||
`<p>.$a$</p>` + nl,
|
||||
},
|
||||
{
|
||||
`$a a$b b$`,
|
||||
`<p><code class="language-math is-loading">a a$b b</code></p>` + nl,
|
||||
`<p>$a a$b b$</p>` + nl,
|
||||
},
|
||||
{
|
||||
`a a$b b`,
|
||||
|
@ -515,7 +523,15 @@ func TestMathBlock(t *testing.T) {
|
|||
},
|
||||
{
|
||||
`a$b $a a$b b$`,
|
||||
`<p>a$b <code class="language-math is-loading">a a$b b</code></p>` + nl,
|
||||
`<p>a$b $a a$b b$</p>` + nl,
|
||||
},
|
||||
{
|
||||
"a$x$",
|
||||
`<p>a$x$</p>` + nl,
|
||||
},
|
||||
{
|
||||
"$x$a",
|
||||
`<p>$x$a</p>` + nl,
|
||||
},
|
||||
{
|
||||
"$$a$$",
|
||||
|
|
|
@ -41,9 +41,12 @@ func (parser *inlineParser) Trigger() []byte {
|
|||
return parser.start[0:1]
|
||||
}
|
||||
|
||||
func isPunctuation(b byte) bool {
|
||||
return b == '.' || b == '!' || b == '?' || b == ',' || b == ';' || b == ':'
|
||||
}
|
||||
|
||||
func isAlphanumeric(b byte) bool {
|
||||
// Github only cares about 0-9A-Za-z
|
||||
return (b >= '0' && b <= '9') || (b >= 'A' && b <= 'Z') || (b >= 'a' && b <= 'z')
|
||||
return (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || (b >= '0' && b <= '9')
|
||||
}
|
||||
|
||||
// Parse parses the current line and returns a result of parsing.
|
||||
|
@ -56,7 +59,7 @@ func (parser *inlineParser) Parse(parent ast.Node, block text.Reader, pc parser.
|
|||
}
|
||||
|
||||
precedingCharacter := block.PrecendingCharacter()
|
||||
if precedingCharacter < 256 && isAlphanumeric(byte(precedingCharacter)) {
|
||||
if precedingCharacter < 256 && (isAlphanumeric(byte(precedingCharacter)) || isPunctuation(byte(precedingCharacter))) {
|
||||
// need to exclude things like `a$` from being considered a start
|
||||
return nil
|
||||
}
|
||||
|
@ -75,14 +78,19 @@ func (parser *inlineParser) Parse(parent ast.Node, block text.Reader, pc parser.
|
|||
ender += pos
|
||||
|
||||
// Now we want to check the character at the end of our parser section
|
||||
// that is ender + len(parser.end)
|
||||
// that is ender + len(parser.end) and check if char before ender is '\'
|
||||
pos = ender + len(parser.end)
|
||||
if len(line) <= pos {
|
||||
break
|
||||
}
|
||||
if !isAlphanumeric(line[pos]) {
|
||||
suceedingCharacter := line[pos]
|
||||
if !isPunctuation(suceedingCharacter) && !(suceedingCharacter == ' ') {
|
||||
return nil
|
||||
}
|
||||
if line[ender-1] != '\\' {
|
||||
break
|
||||
}
|
||||
|
||||
// move the pointer onwards
|
||||
ender += len(parser.end)
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
actions_model "code.gitea.io/gitea/models/actions"
|
||||
activities_model "code.gitea.io/gitea/models/activities"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/organization"
|
||||
|
@ -30,6 +31,7 @@ import (
|
|||
"code.gitea.io/gitea/modules/validation"
|
||||
"code.gitea.io/gitea/modules/web"
|
||||
"code.gitea.io/gitea/routers/api/v1/utils"
|
||||
actions_service "code.gitea.io/gitea/services/actions"
|
||||
"code.gitea.io/gitea/services/context"
|
||||
"code.gitea.io/gitea/services/convert"
|
||||
"code.gitea.io/gitea/services/issue"
|
||||
|
@ -1027,6 +1029,9 @@ func updateRepoArchivedState(ctx *context.APIContext, opts api.EditRepoOption) e
|
|||
ctx.Error(http.StatusInternalServerError, "ArchiveRepoState", err)
|
||||
return err
|
||||
}
|
||||
if err := actions_model.CleanRepoScheduleTasks(ctx, repo); err != nil {
|
||||
log.Error("CleanRepoScheduleTasks for archived repo %s/%s: %v", ctx.Repo.Owner.Name, repo.Name, err)
|
||||
}
|
||||
log.Trace("Repository was archived: %s/%s", ctx.Repo.Owner.Name, repo.Name)
|
||||
} else {
|
||||
if err := repo_model.SetArchiveRepoState(ctx, repo, *opts.Archived); err != nil {
|
||||
|
@ -1034,6 +1039,11 @@ func updateRepoArchivedState(ctx *context.APIContext, opts api.EditRepoOption) e
|
|||
ctx.Error(http.StatusInternalServerError, "ArchiveRepoState", err)
|
||||
return err
|
||||
}
|
||||
if ctx.Repo.Repository.UnitEnabled(ctx, unit_model.TypeActions) {
|
||||
if err := actions_service.DetectAndHandleSchedules(ctx, repo); err != nil {
|
||||
log.Error("DetectAndHandleSchedules for un-archived repo %s/%s: %v", ctx.Repo.Owner.Name, repo.Name, err)
|
||||
}
|
||||
}
|
||||
log.Trace("Repository was un-archived: %s/%s", ctx.Repo.Owner.Name, repo.Name)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
actions_model "code.gitea.io/gitea/models/actions"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/organization"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
|
@ -29,6 +30,7 @@ import (
|
|||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/modules/validation"
|
||||
"code.gitea.io/gitea/modules/web"
|
||||
actions_service "code.gitea.io/gitea/services/actions"
|
||||
asymkey_service "code.gitea.io/gitea/services/asymkey"
|
||||
"code.gitea.io/gitea/services/context"
|
||||
"code.gitea.io/gitea/services/forms"
|
||||
|
@ -929,6 +931,10 @@ func SettingsPost(ctx *context.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
if err := actions_model.CleanRepoScheduleTasks(ctx, repo); err != nil {
|
||||
log.Error("CleanRepoScheduleTasks for archived repo %s/%s: %v", ctx.Repo.Owner.Name, repo.Name, err)
|
||||
}
|
||||
|
||||
ctx.Flash.Success(ctx.Tr("repo.settings.archive.success"))
|
||||
|
||||
log.Trace("Repository was archived: %s/%s", ctx.Repo.Owner.Name, repo.Name)
|
||||
|
@ -947,6 +953,12 @@ func SettingsPost(ctx *context.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
if ctx.Repo.Repository.UnitEnabled(ctx, unit_model.TypeActions) {
|
||||
if err := actions_service.DetectAndHandleSchedules(ctx, repo); err != nil {
|
||||
log.Error("DetectAndHandleSchedules for un-archived repo %s/%s: %v", ctx.Repo.Owner.Name, repo.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
ctx.Flash.Success(ctx.Tr("repo.settings.unarchive.success"))
|
||||
|
||||
log.Trace("Repository was un-archived: %s/%s", ctx.Repo.Owner.Name, repo.Name)
|
||||
|
|
|
@ -119,7 +119,7 @@ func notify(ctx context.Context, input *notifyInput) error {
|
|||
log.Debug("ignore executing %v for event %v whose doer is %v", getMethod(ctx), input.Event, input.Doer.Name)
|
||||
return nil
|
||||
}
|
||||
if input.Repo.IsEmpty {
|
||||
if input.Repo.IsEmpty || input.Repo.IsArchived {
|
||||
return nil
|
||||
}
|
||||
if unit_model.TypeActions.UnitGlobalDisabled() {
|
||||
|
@ -536,7 +536,7 @@ func handleSchedules(
|
|||
|
||||
// DetectAndHandleSchedules detects the schedule workflows on the default branch and create schedule tasks
|
||||
func DetectAndHandleSchedules(ctx context.Context, repo *repo_model.Repository) error {
|
||||
if repo.IsEmpty {
|
||||
if repo.IsEmpty || repo.IsArchived {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -66,6 +66,11 @@ func startTasks(ctx context.Context) error {
|
|||
}
|
||||
}
|
||||
|
||||
if row.Repo.IsArchived {
|
||||
// Skip if the repo is archived
|
||||
continue
|
||||
}
|
||||
|
||||
cfg, err := row.Repo.GetUnit(ctx, unit.TypeActions)
|
||||
if err != nil {
|
||||
if repo_model.IsErrUnitTypeNotExist(err) {
|
||||
|
|
|
@ -967,12 +967,12 @@ func GetPullCommits(ctx *gitea_context.Context, issue *issues_model.Issue) ([]Co
|
|||
for _, commit := range prInfo.Commits {
|
||||
var committerOrAuthorName string
|
||||
var commitTime time.Time
|
||||
if commit.Committer != nil {
|
||||
committerOrAuthorName = commit.Committer.Name
|
||||
commitTime = commit.Committer.When
|
||||
} else {
|
||||
if commit.Author != nil {
|
||||
committerOrAuthorName = commit.Author.Name
|
||||
commitTime = commit.Author.When
|
||||
} else {
|
||||
committerOrAuthorName = commit.Committer.Name
|
||||
commitTime = commit.Committer.When
|
||||
}
|
||||
|
||||
commits = append(commits, CommitInfo{
|
||||
|
|
|
@ -7,14 +7,14 @@
|
|||
<dt>{{ctx.Locale.Tr "admin.config.disable_gravatar"}}</dt>
|
||||
<dd>
|
||||
<div class="ui toggle checkbox" data-tooltip-content="{{ctx.Locale.Tr "admin.config.disable_gravatar"}}">
|
||||
<input type="checkbox" data-config-dyn-key="picture.disable_gravatar" {{if .SystemConfig.Picture.DisableGravatar.Value ctx}}checked{{end}}>
|
||||
<input type="checkbox" data-config-dyn-key="picture.disable_gravatar" {{if .SystemConfig.Picture.DisableGravatar.Value ctx}}checked{{end}}><label></label>
|
||||
</div>
|
||||
</dd>
|
||||
<div class="divider"></div>
|
||||
<dt>{{ctx.Locale.Tr "admin.config.enable_federated_avatar"}}</dt>
|
||||
<dd>
|
||||
<div class="ui toggle checkbox" data-tooltip-content="{{ctx.Locale.Tr "admin.config.enable_federated_avatar"}}">
|
||||
<input type="checkbox" data-config-dyn-key="picture.enable_federated_avatar" {{if .SystemConfig.Picture.EnableFederatedAvatar.Value ctx}}checked{{end}}>
|
||||
<input type="checkbox" data-config-dyn-key="picture.enable_federated_avatar" {{if .SystemConfig.Picture.EnableFederatedAvatar.Value ctx}}checked{{end}}><label></label>
|
||||
</div>
|
||||
</dd>
|
||||
</dl>
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
</div>
|
||||
{{end}}
|
||||
{{if and .Permission.IsAdmin (not .Repository.IsArchived)}}
|
||||
<div class="ui form tw-hidden tw-flex tw-flex-col tw-mt-4" id="topic_edit">
|
||||
<div class="ui form tw-hidden tw-flex tw-gap-2 tw-mt-4" id="topic_edit">
|
||||
<div class="field tw-flex-1 tw-mb-1">
|
||||
<div class="ui fluid multiple search selection dropdown tw-flex-wrap" data-text-count-prompt="{{ctx.Locale.Tr "repo.topic.count_prompt"}}" data-text-format-prompt="{{ctx.Locale.Tr "repo.topic.format_prompt"}}">
|
||||
<input type="hidden" name="topics" value="{{range $i, $v := .Topics}}{{.Name}}{{if Eval $i "+" 1 "<" (len $.Topics)}},{{end}}{{end}}">
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
{{template "repo/header" .}}
|
||||
<div class="ui container">
|
||||
{{template "base/alert" .}}
|
||||
<div class="navbar">
|
||||
<div class="issue-navbar">
|
||||
{{template "repo/issue/navbar" .}}
|
||||
</div>
|
||||
<div class="divider"></div>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<div role="main" aria-label="{{.Title}}" class="page-content repository labels">
|
||||
{{template "repo/header" .}}
|
||||
<div class="ui container">
|
||||
<div class="navbar tw-mb-4">
|
||||
<div class="issue-navbar tw-mb-4">
|
||||
{{template "repo/issue/navbar" .}}
|
||||
{{if and (or .CanWriteIssues .CanWritePulls) (not .Repository.IsArchived)}}
|
||||
<button class="ui small primary new-label button">{{ctx.Locale.Tr "repo.issues.new_label"}}</button>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
{{ctx.Locale.Tr "repo.issues.filter_sort"}}
|
||||
</span>
|
||||
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||
<div class="left menu">
|
||||
<div class="menu">
|
||||
<a class="{{if or (eq .SortType "alphabetically") (not .SortType)}}active {{end}}item" href="?sort=alphabetically&state={{$.State}}">{{ctx.Locale.Tr "repo.issues.label.filter_sort.alphabetically"}}</a>
|
||||
<a class="{{if eq .SortType "reversealphabetically"}}active {{end}}item" href="?sort=reversealphabetically&state={{$.State}}">{{ctx.Locale.Tr "repo.issues.label.filter_sort.reverse_alphabetically"}}</a>
|
||||
<a class="{{if eq .SortType "leastissues"}}active {{end}}item" href="?sort=leastissues&state={{$.State}}">{{ctx.Locale.Tr "repo.milestones.filter_sort.least_issues"}}</a>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<div role="main" aria-label="{{.Title}}" class="page-content repository new milestone">
|
||||
{{template "repo/header" .}}
|
||||
<div class="ui container">
|
||||
<div class="navbar">
|
||||
<div class="issue-navbar">
|
||||
{{template "repo/issue/navbar" .}}
|
||||
{{if and (or .CanWriteIssues .CanWritePulls) .PageIsEditMilestone}}
|
||||
<div class="ui right floated secondary menu">
|
||||
|
|
|
@ -684,7 +684,7 @@
|
|||
{{if and (not (eq .Issue.PullRequest.HeadRepo.FullName .Issue.PullRequest.BaseRepo.FullName)) .CanWriteToHeadRepo}}
|
||||
<div class="divider"></div>
|
||||
<div class="inline field">
|
||||
<div class="ui checkbox" id="allow-edits-from-maintainers"
|
||||
<div class="ui checkbox small-loading-icon" id="allow-edits-from-maintainers"
|
||||
data-url="{{.Issue.Link}}"
|
||||
data-tooltip-content="{{ctx.Locale.Tr "repo.pulls.allow_edits_from_maintainers_desc"}}"
|
||||
data-prompt-error="{{ctx.Locale.Tr "repo.pulls.allow_edits_from_maintainers_err"}}"
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
--repo-header-issue-min-height: 41px;
|
||||
--min-height-textarea: 132px; /* padding + 6 lines + border = calc(1.57142em + 6lh + 2px), but lh is not fully supported */
|
||||
--tab-size: 4;
|
||||
--checkbox-size: 16px; /* height and width of checkbox and radio inputs */
|
||||
}
|
||||
|
||||
:root * {
|
||||
|
|
|
@ -32,10 +32,7 @@ textarea,
|
|||
.ui.form input[type="text"],
|
||||
.ui.form input[type="time"],
|
||||
.ui.form input[type="url"],
|
||||
.ui.selection.dropdown,
|
||||
.ui.checkbox label::before,
|
||||
.ui.checkbox input:checked ~ label::before,
|
||||
.ui.checkbox input:not([type="radio"]):indeterminate ~ label::before {
|
||||
.ui.selection.dropdown {
|
||||
background: var(--color-input-background);
|
||||
border-color: var(--color-input-border);
|
||||
color: var(--color-input-text);
|
||||
|
@ -63,12 +60,7 @@ textarea:hover,
|
|||
.ui.form input[type="text"]:hover,
|
||||
.ui.form input[type="time"]:hover,
|
||||
.ui.form input[type="url"]:hover,
|
||||
.ui.selection.dropdown:hover,
|
||||
.ui.checkbox label:hover::before,
|
||||
.ui.checkbox label:active::before,
|
||||
.ui.radio.checkbox label::after,
|
||||
.ui.radio.checkbox input:focus ~ label::before,
|
||||
.ui.radio.checkbox input:checked ~ label::before {
|
||||
.ui.selection.dropdown:hover {
|
||||
background: var(--color-input-background);
|
||||
border-color: var(--color-input-border-hover);
|
||||
color: var(--color-input-text);
|
||||
|
@ -91,11 +83,7 @@ textarea:focus,
|
|||
.ui.form input[type="text"]:focus,
|
||||
.ui.form input[type="time"]:focus,
|
||||
.ui.form input[type="url"]:focus,
|
||||
.ui.selection.dropdown:focus,
|
||||
.ui.checkbox input:focus ~ label::before,
|
||||
.ui.checkbox input:not([type="radio"]):indeterminate:focus ~ label::before,
|
||||
.ui.checkbox input:checked:focus ~ label::before,
|
||||
.ui.radio.checkbox input:focus:checked ~ label::before {
|
||||
.ui.selection.dropdown:focus {
|
||||
background: var(--color-input-background);
|
||||
border-color: var(--color-primary);
|
||||
color: var(--color-input-text);
|
||||
|
@ -106,58 +94,21 @@ textarea:focus,
|
|||
.ui.form .inline.fields .field > label,
|
||||
.ui.form .inline.fields .field > p,
|
||||
.ui.form .inline.field > label,
|
||||
.ui.form .inline.field > p,
|
||||
.ui.checkbox label,
|
||||
.ui.checkbox + label,
|
||||
.ui.checkbox label:hover,
|
||||
.ui.checkbox + label:hover,
|
||||
.ui.checkbox input:focus ~ label,
|
||||
.ui.checkbox input:active ~ label {
|
||||
.ui.form .inline.field > p {
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.ui.form .required.fields:not(.grouped) > .field > label::after,
|
||||
.ui.form .required.fields.grouped > label::after,
|
||||
.ui.form .required.field > label::after,
|
||||
.ui.form .required.fields:not(.grouped) > .field > .checkbox::after,
|
||||
.ui.form .required.field > .checkbox::after,
|
||||
.ui.form label.required::after {
|
||||
color: var(--color-red);
|
||||
}
|
||||
|
||||
.ui.input,
|
||||
.ui.checkbox input:focus ~ label::after,
|
||||
.ui.checkbox input:checked ~ label::after,
|
||||
.ui.checkbox label:active::after,
|
||||
.ui.checkbox input:not([type="radio"]):indeterminate ~ label::after,
|
||||
.ui.checkbox input:not([type="radio"]):indeterminate:focus ~ label::after,
|
||||
.ui.checkbox input:checked:focus ~ label::after,
|
||||
.ui.disabled.checkbox label,
|
||||
.ui.checkbox input[disabled] ~ label {
|
||||
.ui.input {
|
||||
color: var(--color-input-text);
|
||||
}
|
||||
|
||||
.ui.radio.checkbox input:focus ~ label::after,
|
||||
.ui.radio.checkbox input:checked ~ label::after,
|
||||
.ui.radio.checkbox input:focus:checked ~ label::after {
|
||||
background: var(--color-input-text);
|
||||
}
|
||||
|
||||
.ui.toggle.checkbox label::before {
|
||||
background: var(--color-input-toggle-background);
|
||||
}
|
||||
|
||||
.ui.toggle.checkbox label,
|
||||
.ui.toggle.checkbox input:checked ~ label,
|
||||
.ui.toggle.checkbox input:focus:checked ~ label {
|
||||
color: var(--color-text) !important;
|
||||
}
|
||||
|
||||
.ui.toggle.checkbox input:checked ~ label::before,
|
||||
.ui.toggle.checkbox input:focus:checked ~ label::before {
|
||||
background: var(--color-primary) !important;
|
||||
}
|
||||
|
||||
/* match <select> padding to <input> */
|
||||
.ui.form select {
|
||||
padding: 0.67857143em 1em;
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
@import "./modules/message.css";
|
||||
@import "./modules/table.css";
|
||||
@import "./modules/card.css";
|
||||
@import "./modules/checkbox.css";
|
||||
@import "./modules/modal.css";
|
||||
|
||||
@import "./modules/select.css";
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
.is-loading {
|
||||
pointer-events: none !important;
|
||||
position: relative !important;
|
||||
overflow: hidden !important;
|
||||
}
|
||||
|
||||
.is-loading > * {
|
||||
|
|
120
web_src/css/modules/checkbox.css
Normal file
120
web_src/css/modules/checkbox.css
Normal file
|
@ -0,0 +1,120 @@
|
|||
/* based on Fomantic UI checkbox module, with just the parts extracted that we use. If you find any
|
||||
unused rules here after refactoring, please remove them. */
|
||||
|
||||
input[type="checkbox"],
|
||||
input[type="radio"] {
|
||||
width: var(--checkbox-size);
|
||||
height: var(--checkbox-size);
|
||||
}
|
||||
|
||||
.ui.checkbox {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
vertical-align: baseline;
|
||||
min-height: var(--checkbox-size);
|
||||
line-height: var(--checkbox-size);
|
||||
min-width: var(--checkbox-size);
|
||||
padding: 1px;
|
||||
}
|
||||
|
||||
.ui.checkbox input[type="checkbox"],
|
||||
.ui.checkbox input[type="radio"] {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: var(--checkbox-size);
|
||||
height: var(--checkbox-size);
|
||||
}
|
||||
|
||||
.ui.checkbox input[type="checkbox"]:enabled,
|
||||
.ui.checkbox input[type="radio"]:enabled,
|
||||
.ui.checkbox label:enabled {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.ui.checkbox label {
|
||||
cursor: auto;
|
||||
position: relative;
|
||||
display: block;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.ui.checkbox label,
|
||||
.ui.radio.checkbox label {
|
||||
margin-left: 1.85714em;
|
||||
}
|
||||
|
||||
.ui.checkbox + label {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.ui.disabled.checkbox label,
|
||||
.ui.checkbox input[disabled] ~ label {
|
||||
cursor: default !important;
|
||||
opacity: 0.5;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.ui.radio.checkbox {
|
||||
min-height: var(--checkbox-size);
|
||||
}
|
||||
|
||||
/* "switch" styled checkbox */
|
||||
|
||||
.ui.toggle.checkbox {
|
||||
min-height: 1.5rem;
|
||||
}
|
||||
.ui.toggle.checkbox input {
|
||||
width: 3.5rem;
|
||||
height: 1.5rem;
|
||||
opacity: 0;
|
||||
z-index: 3;
|
||||
}
|
||||
.ui.toggle.checkbox label {
|
||||
min-height: 1.5rem;
|
||||
padding-left: 4.5rem;
|
||||
padding-top: 0.15em;
|
||||
}
|
||||
.ui.toggle.checkbox label::before {
|
||||
display: block;
|
||||
position: absolute;
|
||||
content: "";
|
||||
z-index: 1;
|
||||
top: 0;
|
||||
width: 3.5rem;
|
||||
height: 1.5rem;
|
||||
border-radius: 500rem;
|
||||
left: 0;
|
||||
}
|
||||
.ui.toggle.checkbox label::after {
|
||||
background: var(--color-white);
|
||||
position: absolute;
|
||||
content: "";
|
||||
opacity: 1;
|
||||
z-index: 2;
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
top: 0;
|
||||
left: 0;
|
||||
border-radius: 500rem;
|
||||
transition: background 0.3s ease, left 0.3s ease;
|
||||
}
|
||||
.ui.toggle.checkbox input ~ label::after {
|
||||
left: -0.05rem;
|
||||
}
|
||||
.ui.toggle.checkbox input:checked ~ label::after {
|
||||
left: 2.15rem;
|
||||
}
|
||||
.ui.toggle.checkbox input:focus ~ label::before,
|
||||
.ui.toggle.checkbox label::before {
|
||||
background: var(--color-input-toggle-background);
|
||||
}
|
||||
.ui.toggle.checkbox label,
|
||||
.ui.toggle.checkbox input:checked ~ label,
|
||||
.ui.toggle.checkbox input:focus:checked ~ label {
|
||||
color: var(--color-text) !important;
|
||||
}
|
||||
.ui.toggle.checkbox input:checked ~ label::before,
|
||||
.ui.toggle.checkbox input:focus:checked ~ label::before {
|
||||
background: var(--color-primary) !important;
|
||||
}
|
|
@ -135,6 +135,12 @@ h4.ui.header .sub.header {
|
|||
font-weight: var(--font-weight-normal);
|
||||
}
|
||||
|
||||
/* open dropdown menus to the left in right-attached headers */
|
||||
.ui.attached.header > .ui.right .ui.dropdown .menu {
|
||||
right: 0;
|
||||
left: auto;
|
||||
}
|
||||
|
||||
/* if a .top.attached.header is followed by a .segment, add some margin */
|
||||
.ui.segments + .ui.top.attached.header,
|
||||
.ui.attached.segment + .ui.top.attached.header {
|
||||
|
|
|
@ -140,3 +140,8 @@
|
|||
.secondary-nav {
|
||||
background: var(--color-secondary-nav-bg) !important; /* important because of .ui.secondary.menu */
|
||||
}
|
||||
|
||||
.issue-navbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
|
|
@ -89,10 +89,6 @@
|
|||
text-align: center;
|
||||
}
|
||||
|
||||
.organization.options input {
|
||||
min-width: 300px;
|
||||
}
|
||||
|
||||
.page-content.organization .org-avatar {
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
|
|
@ -2990,6 +2990,7 @@ tbody.commit-list {
|
|||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
@media (max-width: 767.98px) {
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
.issue-list-toolbar-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.issue-list-toolbar-right .filter.menu {
|
||||
|
|
709
web_src/fomantic/build/semantic.css
generated
709
web_src/fomantic/build/semantic.css
generated
|
@ -2323,715 +2323,6 @@
|
|||
Theme Overrides
|
||||
*******************************/
|
||||
|
||||
/*******************************
|
||||
Site Overrides
|
||||
*******************************/
|
||||
/*!
|
||||
* # Fomantic-UI - Checkbox
|
||||
* http://github.com/fomantic/Fomantic-UI/
|
||||
*
|
||||
*
|
||||
* Released under the MIT license
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
*/
|
||||
|
||||
/*******************************
|
||||
Checkbox
|
||||
*******************************/
|
||||
|
||||
/*--------------
|
||||
Content
|
||||
---------------*/
|
||||
|
||||
.ui.checkbox {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
backface-visibility: hidden;
|
||||
outline: none;
|
||||
vertical-align: baseline;
|
||||
font-style: normal;
|
||||
min-height: 17px;
|
||||
font-size: 1em;
|
||||
line-height: 17px;
|
||||
min-width: 17px;
|
||||
}
|
||||
|
||||
/* HTML Checkbox */
|
||||
|
||||
.ui.checkbox input[type="checkbox"],
|
||||
.ui.checkbox input[type="radio"] {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
opacity: 0 !important;
|
||||
outline: none;
|
||||
z-index: 3;
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
}
|
||||
|
||||
.ui.checkbox label {
|
||||
cursor: auto;
|
||||
position: relative;
|
||||
display: block;
|
||||
padding-left: 1.85714em;
|
||||
outline: none;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.ui.checkbox label:before {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
content: '';
|
||||
background: #FFFFFF;
|
||||
border-radius: 0.21428571rem;
|
||||
transition: border 0.1s ease, opacity 0.1s ease, transform 0.1s ease, box-shadow 0.1s ease;
|
||||
border: 1px solid #D4D4D5;
|
||||
}
|
||||
|
||||
/*--------------
|
||||
Checkmark
|
||||
---------------*/
|
||||
|
||||
.ui.checkbox label:after {
|
||||
position: absolute;
|
||||
font-size: 14px;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
text-align: center;
|
||||
opacity: 0;
|
||||
color: rgba(0, 0, 0, 0.87);
|
||||
transition: border 0.1s ease, opacity 0.1s ease, transform 0.1s ease, box-shadow 0.1s ease;
|
||||
}
|
||||
|
||||
/*--------------
|
||||
Label
|
||||
---------------*/
|
||||
|
||||
/* Inside */
|
||||
|
||||
.ui.checkbox label,
|
||||
.ui.checkbox + label {
|
||||
color: rgba(0, 0, 0, 0.87);
|
||||
transition: color 0.1s ease;
|
||||
}
|
||||
|
||||
/* Outside */
|
||||
|
||||
.ui.checkbox + label {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/*******************************
|
||||
States
|
||||
*******************************/
|
||||
|
||||
/*--------------
|
||||
Hover
|
||||
---------------*/
|
||||
|
||||
.ui.checkbox label:hover::before {
|
||||
background: #FFFFFF;
|
||||
border-color: rgba(34, 36, 38, 0.35);
|
||||
}
|
||||
|
||||
.ui.checkbox label:hover,
|
||||
.ui.checkbox + label:hover {
|
||||
color: rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
|
||||
/*--------------
|
||||
Down
|
||||
---------------*/
|
||||
|
||||
.ui.checkbox label:active::before {
|
||||
background: #F9FAFB;
|
||||
border-color: rgba(34, 36, 38, 0.35);
|
||||
}
|
||||
|
||||
.ui.checkbox label:active::after {
|
||||
color: rgba(0, 0, 0, 0.95);
|
||||
}
|
||||
|
||||
.ui.checkbox input:active ~ label {
|
||||
color: rgba(0, 0, 0, 0.95);
|
||||
}
|
||||
|
||||
/*--------------
|
||||
Focus
|
||||
---------------*/
|
||||
|
||||
.ui.checkbox input:focus ~ label:before {
|
||||
background: #FFFFFF;
|
||||
border-color: #96C8DA;
|
||||
}
|
||||
|
||||
.ui.checkbox input:focus ~ label:after {
|
||||
color: rgba(0, 0, 0, 0.95);
|
||||
}
|
||||
|
||||
.ui.checkbox input:focus ~ label {
|
||||
color: rgba(0, 0, 0, 0.95);
|
||||
}
|
||||
|
||||
/*--------------
|
||||
Active
|
||||
---------------*/
|
||||
|
||||
.ui.checkbox input:checked ~ label:before {
|
||||
background: #FFFFFF;
|
||||
border-color: rgba(34, 36, 38, 0.35);
|
||||
}
|
||||
|
||||
.ui.checkbox input:checked ~ label:after {
|
||||
opacity: 1;
|
||||
color: rgba(0, 0, 0, 0.95);
|
||||
}
|
||||
|
||||
/*--------------
|
||||
Indeterminate
|
||||
---------------*/
|
||||
|
||||
.ui.checkbox input:not([type=radio]):indeterminate ~ label:before {
|
||||
background: #FFFFFF;
|
||||
border-color: rgba(34, 36, 38, 0.35);
|
||||
}
|
||||
|
||||
.ui.checkbox input:not([type=radio]):indeterminate ~ label:after {
|
||||
opacity: 1;
|
||||
color: rgba(0, 0, 0, 0.95);
|
||||
}
|
||||
|
||||
.ui.indeterminate.toggle.checkbox input:not([type=radio]):indeterminate ~ label:before {
|
||||
background: rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.ui.indeterminate.toggle.checkbox input:not([type=radio]) ~ label:after {
|
||||
left: 1.075rem;
|
||||
}
|
||||
|
||||
/*--------------
|
||||
Active Focus
|
||||
---------------*/
|
||||
|
||||
.ui.checkbox input:not([type=radio]):indeterminate:focus ~ label:before,
|
||||
.ui.checkbox input:checked:focus ~ label:before {
|
||||
background: #FFFFFF;
|
||||
border-color: #96C8DA;
|
||||
}
|
||||
|
||||
.ui.checkbox input:not([type=radio]):indeterminate:focus ~ label:after,
|
||||
.ui.checkbox input:checked:focus ~ label:after {
|
||||
color: rgba(0, 0, 0, 0.95);
|
||||
}
|
||||
|
||||
/*--------------
|
||||
Read-Only
|
||||
---------------*/
|
||||
|
||||
.ui.read-only.checkbox,
|
||||
.ui.read-only.checkbox label {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/*--------------
|
||||
Disabled
|
||||
---------------*/
|
||||
|
||||
.ui.disabled.checkbox label,
|
||||
.ui.checkbox input[disabled] ~ label {
|
||||
cursor: default !important;
|
||||
opacity: 0.5;
|
||||
color: #000000;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/*--------------
|
||||
Hidden
|
||||
---------------*/
|
||||
|
||||
/* Initialized checkbox moves input below element
|
||||
to prevent manually triggering */
|
||||
|
||||
.ui.checkbox input.hidden {
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
/* Selectable Label */
|
||||
|
||||
.ui.checkbox input.hidden + label {
|
||||
cursor: pointer;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
/*******************************
|
||||
Types
|
||||
*******************************/
|
||||
|
||||
/*--------------
|
||||
Radio
|
||||
---------------*/
|
||||
|
||||
.ui.radio.checkbox {
|
||||
min-height: 15px;
|
||||
}
|
||||
|
||||
.ui.radio.checkbox label {
|
||||
padding-left: 1.85714em;
|
||||
}
|
||||
|
||||
/* Box */
|
||||
|
||||
.ui.radio.checkbox label:before {
|
||||
content: '';
|
||||
transform: none;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
border-radius: 500rem;
|
||||
top: 1px;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
/* Bullet */
|
||||
|
||||
.ui.radio.checkbox label:after {
|
||||
border: none;
|
||||
content: '' !important;
|
||||
line-height: 15px;
|
||||
top: 1px;
|
||||
left: 0;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
border-radius: 500rem;
|
||||
transform: scale(0.46666667);
|
||||
background-color: rgba(0, 0, 0, 0.87);
|
||||
}
|
||||
|
||||
/* Focus */
|
||||
|
||||
.ui.radio.checkbox input:focus ~ label:before {
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
|
||||
.ui.radio.checkbox input:focus ~ label:after {
|
||||
background-color: rgba(0, 0, 0, 0.95);
|
||||
}
|
||||
|
||||
/* Indeterminate */
|
||||
|
||||
.ui.radio.checkbox input:indeterminate ~ label:after {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* Active */
|
||||
|
||||
.ui.radio.checkbox input:checked ~ label:before {
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
|
||||
.ui.radio.checkbox input:checked ~ label:after {
|
||||
background-color: rgba(0, 0, 0, 0.95);
|
||||
}
|
||||
|
||||
/* Active Focus */
|
||||
|
||||
.ui.radio.checkbox input:focus:checked ~ label:before {
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
|
||||
.ui.radio.checkbox input:focus:checked ~ label:after {
|
||||
background-color: rgba(0, 0, 0, 0.95);
|
||||
}
|
||||
|
||||
/*--------------
|
||||
Slider
|
||||
---------------*/
|
||||
|
||||
.ui.slider.checkbox {
|
||||
min-height: 1.25rem;
|
||||
}
|
||||
|
||||
/* Input */
|
||||
|
||||
.ui.slider.checkbox input {
|
||||
width: 3.5rem;
|
||||
height: 1.25rem;
|
||||
}
|
||||
|
||||
/* Label */
|
||||
|
||||
.ui.slider.checkbox label {
|
||||
padding-left: 4.5rem;
|
||||
line-height: 1rem;
|
||||
color: rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
/* Line */
|
||||
|
||||
.ui.slider.checkbox label:before {
|
||||
display: block;
|
||||
position: absolute;
|
||||
content: '';
|
||||
transform: none;
|
||||
border: none !important;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
top: 0.4rem;
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
width: 3.5rem;
|
||||
height: 0.21428571rem;
|
||||
border-radius: 500rem;
|
||||
transition: background 0.3s ease;
|
||||
}
|
||||
|
||||
/* Handle */
|
||||
|
||||
.ui.slider.checkbox label:after {
|
||||
background: #FFFFFF linear-gradient(transparent, rgba(0, 0, 0, 0.05));
|
||||
position: absolute;
|
||||
content: '' !important;
|
||||
opacity: 1;
|
||||
z-index: 2;
|
||||
border: none;
|
||||
box-shadow: 0 1px 2px 0 rgba(34, 36, 38, 0.15), 0 0 0 1px rgba(34, 36, 38, 0.15) inset;
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
top: -0.25rem;
|
||||
left: 0;
|
||||
transform: none;
|
||||
border-radius: 500rem;
|
||||
transition: left 0.3s ease;
|
||||
}
|
||||
|
||||
/* Focus */
|
||||
|
||||
.ui.slider.checkbox input:focus ~ label:before {
|
||||
background-color: rgba(0, 0, 0, 0.15);
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* Hover */
|
||||
|
||||
.ui.slider.checkbox label:hover {
|
||||
color: rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
|
||||
.ui.slider.checkbox label:hover::before {
|
||||
background: rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
/* Active */
|
||||
|
||||
.ui.slider.checkbox input:checked ~ label {
|
||||
color: rgba(0, 0, 0, 0.95) !important;
|
||||
}
|
||||
|
||||
.ui.slider.checkbox input:checked ~ label:before {
|
||||
background-color: #545454 !important;
|
||||
}
|
||||
|
||||
.ui.slider.checkbox input:checked ~ label:after {
|
||||
left: 2rem;
|
||||
}
|
||||
|
||||
/* Active Focus */
|
||||
|
||||
.ui.slider.checkbox input:focus:checked ~ label {
|
||||
color: rgba(0, 0, 0, 0.95) !important;
|
||||
}
|
||||
|
||||
.ui.slider.checkbox input:focus:checked ~ label:before {
|
||||
background-color: #000000 !important;
|
||||
}
|
||||
|
||||
/*--------------
|
||||
Toggle
|
||||
---------------*/
|
||||
|
||||
.ui.toggle.checkbox {
|
||||
min-height: 1.5rem;
|
||||
}
|
||||
|
||||
/* Input */
|
||||
|
||||
.ui.toggle.checkbox input {
|
||||
width: 3.5rem;
|
||||
height: 1.5rem;
|
||||
}
|
||||
|
||||
/* Label */
|
||||
|
||||
.ui.toggle.checkbox label {
|
||||
min-height: 1.5rem;
|
||||
padding-left: 4.5rem;
|
||||
color: rgba(0, 0, 0, 0.87);
|
||||
}
|
||||
|
||||
.ui.toggle.checkbox label {
|
||||
padding-top: 0.15em;
|
||||
}
|
||||
|
||||
/* Switch */
|
||||
|
||||
.ui.toggle.checkbox label:before {
|
||||
display: block;
|
||||
position: absolute;
|
||||
content: '';
|
||||
z-index: 1;
|
||||
transform: none;
|
||||
border: none;
|
||||
top: 0;
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
box-shadow: none;
|
||||
width: 3.5rem;
|
||||
height: 1.5rem;
|
||||
border-radius: 500rem;
|
||||
}
|
||||
|
||||
/* Handle */
|
||||
|
||||
.ui.toggle.checkbox label:after {
|
||||
background: #FFFFFF linear-gradient(transparent, rgba(0, 0, 0, 0.05));
|
||||
position: absolute;
|
||||
content: '' !important;
|
||||
opacity: 1;
|
||||
z-index: 2;
|
||||
border: none;
|
||||
box-shadow: 0 1px 2px 0 rgba(34, 36, 38, 0.15), 0 0 0 1px rgba(34, 36, 38, 0.15) inset;
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
top: 0;
|
||||
left: 0;
|
||||
border-radius: 500rem;
|
||||
transition: background 0.3s ease, left 0.3s ease;
|
||||
}
|
||||
|
||||
.ui.toggle.checkbox input ~ label:after {
|
||||
left: -0.05rem;
|
||||
box-shadow: 0 1px 2px 0 rgba(34, 36, 38, 0.15), 0 0 0 1px rgba(34, 36, 38, 0.15) inset;
|
||||
}
|
||||
|
||||
/* Focus */
|
||||
|
||||
.ui.toggle.checkbox input:focus ~ label:before {
|
||||
background-color: rgba(0, 0, 0, 0.15);
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* Hover */
|
||||
|
||||
.ui.toggle.checkbox label:hover::before {
|
||||
background-color: rgba(0, 0, 0, 0.15);
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* Active */
|
||||
|
||||
.ui.toggle.checkbox input:checked ~ label {
|
||||
color: rgba(0, 0, 0, 0.95) !important;
|
||||
}
|
||||
|
||||
.ui.toggle.checkbox input:checked ~ label:before {
|
||||
background-color: #2185D0 !important;
|
||||
}
|
||||
|
||||
.ui.toggle.checkbox input:checked ~ label:after {
|
||||
left: 2.15rem;
|
||||
box-shadow: 0 1px 2px 0 rgba(34, 36, 38, 0.15), 0 0 0 1px rgba(34, 36, 38, 0.15) inset;
|
||||
}
|
||||
|
||||
/* Active Focus */
|
||||
|
||||
.ui.toggle.checkbox input:focus:checked ~ label {
|
||||
color: rgba(0, 0, 0, 0.95) !important;
|
||||
}
|
||||
|
||||
.ui.toggle.checkbox input:focus:checked ~ label:before {
|
||||
background-color: #0d71bb !important;
|
||||
}
|
||||
|
||||
/*******************************
|
||||
Variations
|
||||
*******************************/
|
||||
|
||||
/*--------------
|
||||
Fitted
|
||||
---------------*/
|
||||
|
||||
.ui.fitted.checkbox label {
|
||||
padding-left: 0 !important;
|
||||
}
|
||||
|
||||
.ui.fitted.toggle.checkbox {
|
||||
width: 3.5rem;
|
||||
}
|
||||
|
||||
.ui.fitted.slider.checkbox {
|
||||
width: 3.5rem;
|
||||
}
|
||||
|
||||
/*--------------------
|
||||
Size
|
||||
---------------------*/
|
||||
|
||||
.ui.mini.checkbox {
|
||||
font-size: 0.78571429em;
|
||||
}
|
||||
|
||||
.ui.tiny.checkbox {
|
||||
font-size: 0.85714286em;
|
||||
}
|
||||
|
||||
.ui.small.checkbox {
|
||||
font-size: 0.92857143em;
|
||||
}
|
||||
|
||||
.ui.large.checkbox {
|
||||
font-size: 1.14285714em;
|
||||
}
|
||||
|
||||
.ui.large.form .checkbox:not(.slider):not(.toggle):not(.radio) label:after,
|
||||
.ui.large.checkbox:not(.slider):not(.toggle):not(.radio) label:after,
|
||||
.ui.large.form .checkbox:not(.slider):not(.toggle):not(.radio) label:before,
|
||||
.ui.large.checkbox:not(.slider):not(.toggle):not(.radio) label:before {
|
||||
transform: scale(1.14285714);
|
||||
transform-origin: left;
|
||||
}
|
||||
|
||||
.ui.large.form .checkbox.radio label:before,
|
||||
.ui.large.checkbox.radio label:before {
|
||||
transform: scale(1.14285714);
|
||||
transform-origin: left;
|
||||
}
|
||||
|
||||
.ui.large.form .checkbox.radio label:after,
|
||||
.ui.large.checkbox.radio label:after {
|
||||
transform: scale(0.57142857);
|
||||
transform-origin: left;
|
||||
left: 0.33571429em;
|
||||
}
|
||||
|
||||
.ui.big.checkbox {
|
||||
font-size: 1.28571429em;
|
||||
}
|
||||
|
||||
.ui.big.form .checkbox:not(.slider):not(.toggle):not(.radio) label:after,
|
||||
.ui.big.checkbox:not(.slider):not(.toggle):not(.radio) label:after,
|
||||
.ui.big.form .checkbox:not(.slider):not(.toggle):not(.radio) label:before,
|
||||
.ui.big.checkbox:not(.slider):not(.toggle):not(.radio) label:before {
|
||||
transform: scale(1.28571429);
|
||||
transform-origin: left;
|
||||
}
|
||||
|
||||
.ui.big.form .checkbox.radio label:before,
|
||||
.ui.big.checkbox.radio label:before {
|
||||
transform: scale(1.28571429);
|
||||
transform-origin: left;
|
||||
}
|
||||
|
||||
.ui.big.form .checkbox.radio label:after,
|
||||
.ui.big.checkbox.radio label:after {
|
||||
transform: scale(0.64285714);
|
||||
transform-origin: left;
|
||||
left: 0.37142857em;
|
||||
}
|
||||
|
||||
.ui.huge.checkbox {
|
||||
font-size: 1.42857143em;
|
||||
}
|
||||
|
||||
.ui.huge.form .checkbox:not(.slider):not(.toggle):not(.radio) label:after,
|
||||
.ui.huge.checkbox:not(.slider):not(.toggle):not(.radio) label:after,
|
||||
.ui.huge.form .checkbox:not(.slider):not(.toggle):not(.radio) label:before,
|
||||
.ui.huge.checkbox:not(.slider):not(.toggle):not(.radio) label:before {
|
||||
transform: scale(1.42857143);
|
||||
transform-origin: left;
|
||||
}
|
||||
|
||||
.ui.huge.form .checkbox.radio label:before,
|
||||
.ui.huge.checkbox.radio label:before {
|
||||
transform: scale(1.42857143);
|
||||
transform-origin: left;
|
||||
}
|
||||
|
||||
.ui.huge.form .checkbox.radio label:after,
|
||||
.ui.huge.checkbox.radio label:after {
|
||||
transform: scale(0.71428571);
|
||||
transform-origin: left;
|
||||
left: 0.40714286em;
|
||||
}
|
||||
|
||||
.ui.massive.checkbox {
|
||||
font-size: 1.71428571em;
|
||||
}
|
||||
|
||||
.ui.massive.form .checkbox:not(.slider):not(.toggle):not(.radio) label:after,
|
||||
.ui.massive.checkbox:not(.slider):not(.toggle):not(.radio) label:after,
|
||||
.ui.massive.form .checkbox:not(.slider):not(.toggle):not(.radio) label:before,
|
||||
.ui.massive.checkbox:not(.slider):not(.toggle):not(.radio) label:before {
|
||||
transform: scale(1.71428571);
|
||||
transform-origin: left;
|
||||
}
|
||||
|
||||
.ui.massive.form .checkbox.radio label:before,
|
||||
.ui.massive.checkbox.radio label:before {
|
||||
transform: scale(1.71428571);
|
||||
transform-origin: left;
|
||||
}
|
||||
|
||||
.ui.massive.form .checkbox.radio label:after,
|
||||
.ui.massive.checkbox.radio label:after {
|
||||
transform: scale(0.85714286);
|
||||
transform-origin: left;
|
||||
left: 0.47857143em;
|
||||
}
|
||||
|
||||
/*******************************
|
||||
Theme Overrides
|
||||
*******************************/
|
||||
|
||||
@font-face {
|
||||
font-family: 'Checkbox';
|
||||
src: url(data:application/x-font-ttf;charset=utf-8;base64,AAEAAAALAIAAAwAwT1MvMg8SBD8AAAC8AAAAYGNtYXAYVtCJAAABHAAAAFRnYXNwAAAAEAAAAXAAAAAIZ2x5Zn4huwUAAAF4AAABYGhlYWQGPe1ZAAAC2AAAADZoaGVhB30DyAAAAxAAAAAkaG10eBBKAEUAAAM0AAAAHGxvY2EAmgESAAADUAAAABBtYXhwAAkALwAAA2AAAAAgbmFtZSC8IugAAAOAAAABknBvc3QAAwAAAAAFFAAAACAAAwMTAZAABQAAApkCzAAAAI8CmQLMAAAB6wAzAQkAAAAAAAAAAAAAAAAAAAABEAAAAAAAAAAAAAAAAAAAAABAAADoAgPA/8AAQAPAAEAAAAABAAAAAAAAAAAAAAAgAAAAAAADAAAAAwAAABwAAQADAAAAHAADAAEAAAAcAAQAOAAAAAoACAACAAIAAQAg6AL//f//AAAAAAAg6AD//f//AAH/4xgEAAMAAQAAAAAAAAAAAAAAAQAB//8ADwABAAAAAAAAAAAAAgAANzkBAAAAAAEAAAAAAAAAAAACAAA3OQEAAAAAAQAAAAAAAAAAAAIAADc5AQAAAAABAEUAUQO7AvgAGgAAARQHAQYjIicBJjU0PwE2MzIfAQE2MzIfARYVA7sQ/hQQFhcQ/uMQEE4QFxcQqAF2EBcXEE4QAnMWEP4UEBABHRAXFhBOEBCoAXcQEE4QFwAAAAABAAABbgMlAkkAFAAAARUUBwYjISInJj0BNDc2MyEyFxYVAyUQEBf9SRcQEBAQFwK3FxAQAhJtFxAQEBAXbRcQEBAQFwAAAAABAAAASQMlA24ALAAAARUUBwYrARUUBwYrASInJj0BIyInJj0BNDc2OwE1NDc2OwEyFxYdATMyFxYVAyUQEBfuEBAXbhYQEO4XEBAQEBfuEBAWbhcQEO4XEBACEm0XEBDuFxAQEBAX7hAQF20XEBDuFxAQEBAX7hAQFwAAAQAAAAIAAHRSzT9fDzz1AAsEAAAAAADRsdR3AAAAANGx1HcAAAAAA7sDbgAAAAgAAgAAAAAAAAABAAADwP/AAAAEAAAAAAADuwABAAAAAAAAAAAAAAAAAAAABwQAAAAAAAAAAAAAAAIAAAAEAABFAyUAAAMlAAAAAAAAAAoAFAAeAE4AcgCwAAEAAAAHAC0AAQAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAOAK4AAQAAAAAAAQAIAAAAAQAAAAAAAgAHAGkAAQAAAAAAAwAIADkAAQAAAAAABAAIAH4AAQAAAAAABQALABgAAQAAAAAABgAIAFEAAQAAAAAACgAaAJYAAwABBAkAAQAQAAgAAwABBAkAAgAOAHAAAwABBAkAAwAQAEEAAwABBAkABAAQAIYAAwABBAkABQAWACMAAwABBAkABgAQAFkAAwABBAkACgA0ALBDaGVja2JveABDAGgAZQBjAGsAYgBvAHhWZXJzaW9uIDIuMABWAGUAcgBzAGkAbwBuACAAMgAuADBDaGVja2JveABDAGgAZQBjAGsAYgBvAHhDaGVja2JveABDAGgAZQBjAGsAYgBvAHhSZWd1bGFyAFIAZQBnAHUAbABhAHJDaGVja2JveABDAGgAZQBjAGsAYgBvAHhGb250IGdlbmVyYXRlZCBieSBJY29Nb29uLgBGAG8AbgB0ACAAZwBlAG4AZQByAGEAdABlAGQAIABiAHkAIABJAGMAbwBNAG8AbwBuAC4AAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) format('truetype');
|
||||
}
|
||||
|
||||
/* Checkmark */
|
||||
|
||||
.ui.checkbox label:after,
|
||||
.ui.checkbox .box:after {
|
||||
font-family: 'Checkbox';
|
||||
}
|
||||
|
||||
/* Checked */
|
||||
|
||||
.ui.checkbox input:checked ~ .box:after,
|
||||
.ui.checkbox input:checked ~ label:after {
|
||||
content: '\e800';
|
||||
}
|
||||
|
||||
/* Indeterminate */
|
||||
|
||||
.ui.checkbox input:indeterminate ~ .box:after,
|
||||
.ui.checkbox input:indeterminate ~ label:after {
|
||||
font-size: 12px;
|
||||
content: '\e801';
|
||||
}
|
||||
|
||||
/* UTF Reference
|
||||
.check:before { content: '\e800'; }
|
||||
.dash:before { content: '\e801'; }
|
||||
.plus:before { content: '\e802'; }
|
||||
*/
|
||||
|
||||
/*******************************
|
||||
Site Overrides
|
||||
*******************************/
|
||||
|
|
877
web_src/fomantic/build/semantic.js
generated
877
web_src/fomantic/build/semantic.js
generated
|
@ -1184,883 +1184,6 @@ $.api.settings = {
|
|||
|
||||
|
||||
|
||||
})( jQuery, window, document );
|
||||
|
||||
/*!
|
||||
* # Fomantic-UI - Checkbox
|
||||
* http://github.com/fomantic/Fomantic-UI/
|
||||
*
|
||||
*
|
||||
* Released under the MIT license
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
*/
|
||||
|
||||
;(function ($, window, document, undefined) {
|
||||
|
||||
'use strict';
|
||||
|
||||
$.isFunction = $.isFunction || function(obj) {
|
||||
return typeof obj === "function" && typeof obj.nodeType !== "number";
|
||||
};
|
||||
|
||||
window = (typeof window != 'undefined' && window.Math == Math)
|
||||
? window
|
||||
: (typeof self != 'undefined' && self.Math == Math)
|
||||
? self
|
||||
: Function('return this')()
|
||||
;
|
||||
|
||||
$.fn.checkbox = function(parameters) {
|
||||
var
|
||||
$allModules = $(this),
|
||||
moduleSelector = $allModules.selector || '',
|
||||
|
||||
time = new Date().getTime(),
|
||||
performance = [],
|
||||
|
||||
query = arguments[0],
|
||||
methodInvoked = (typeof query == 'string'),
|
||||
queryArguments = [].slice.call(arguments, 1),
|
||||
returnedValue
|
||||
;
|
||||
|
||||
$allModules
|
||||
.each(function() {
|
||||
var
|
||||
settings = $.extend(true, {}, $.fn.checkbox.settings, parameters),
|
||||
|
||||
className = settings.className,
|
||||
namespace = settings.namespace,
|
||||
selector = settings.selector,
|
||||
error = settings.error,
|
||||
|
||||
eventNamespace = '.' + namespace,
|
||||
moduleNamespace = 'module-' + namespace,
|
||||
|
||||
$module = $(this),
|
||||
$label = $(this).children(selector.label),
|
||||
$input = $(this).children(selector.input),
|
||||
input = $input[0],
|
||||
|
||||
initialLoad = false,
|
||||
shortcutPressed = false,
|
||||
instance = $module.data(moduleNamespace),
|
||||
|
||||
observer,
|
||||
element = this,
|
||||
module
|
||||
;
|
||||
|
||||
module = {
|
||||
|
||||
initialize: function() {
|
||||
module.verbose('Initializing checkbox', settings);
|
||||
|
||||
module.create.label();
|
||||
module.bind.events();
|
||||
|
||||
module.set.tabbable();
|
||||
module.hide.input();
|
||||
|
||||
module.observeChanges();
|
||||
module.instantiate();
|
||||
module.setup();
|
||||
},
|
||||
|
||||
instantiate: function() {
|
||||
module.verbose('Storing instance of module', module);
|
||||
instance = module;
|
||||
$module
|
||||
.data(moduleNamespace, module)
|
||||
;
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
module.verbose('Destroying module');
|
||||
module.unbind.events();
|
||||
module.show.input();
|
||||
$module.removeData(moduleNamespace);
|
||||
},
|
||||
|
||||
fix: {
|
||||
reference: function() {
|
||||
if( $module.is(selector.input) ) {
|
||||
module.debug('Behavior called on <input> adjusting invoked element');
|
||||
$module = $module.closest(selector.checkbox);
|
||||
module.refresh();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
setup: function() {
|
||||
module.set.initialLoad();
|
||||
if( module.is.indeterminate() ) {
|
||||
module.debug('Initial value is indeterminate');
|
||||
module.indeterminate();
|
||||
}
|
||||
else if( module.is.checked() ) {
|
||||
module.debug('Initial value is checked');
|
||||
module.check();
|
||||
}
|
||||
else {
|
||||
module.debug('Initial value is unchecked');
|
||||
module.uncheck();
|
||||
}
|
||||
module.remove.initialLoad();
|
||||
},
|
||||
|
||||
refresh: function() {
|
||||
$label = $module.children(selector.label);
|
||||
$input = $module.children(selector.input);
|
||||
input = $input[0];
|
||||
},
|
||||
|
||||
hide: {
|
||||
input: function() {
|
||||
module.verbose('Modifying <input> z-index to be unselectable');
|
||||
$input.addClass(className.hidden);
|
||||
}
|
||||
},
|
||||
show: {
|
||||
input: function() {
|
||||
module.verbose('Modifying <input> z-index to be selectable');
|
||||
$input.removeClass(className.hidden);
|
||||
}
|
||||
},
|
||||
|
||||
observeChanges: function() {
|
||||
if('MutationObserver' in window) {
|
||||
observer = new MutationObserver(function(mutations) {
|
||||
module.debug('DOM tree modified, updating selector cache');
|
||||
module.refresh();
|
||||
});
|
||||
observer.observe(element, {
|
||||
childList : true,
|
||||
subtree : true
|
||||
});
|
||||
module.debug('Setting up mutation observer', observer);
|
||||
}
|
||||
},
|
||||
|
||||
attachEvents: function(selector, event) {
|
||||
var
|
||||
$element = $(selector)
|
||||
;
|
||||
event = $.isFunction(module[event])
|
||||
? module[event]
|
||||
: module.toggle
|
||||
;
|
||||
if($element.length > 0) {
|
||||
module.debug('Attaching checkbox events to element', selector, event);
|
||||
$element
|
||||
.on('click' + eventNamespace, event)
|
||||
;
|
||||
}
|
||||
else {
|
||||
module.error(error.notFound);
|
||||
}
|
||||
},
|
||||
|
||||
preventDefaultOnInputTarget: function() {
|
||||
if(typeof event !== 'undefined' && event !== null && $(event.target).is(selector.input)) {
|
||||
module.verbose('Preventing default check action after manual check action');
|
||||
event.preventDefault();
|
||||
}
|
||||
},
|
||||
|
||||
event: {
|
||||
change: function(event) {
|
||||
if( !module.should.ignoreCallbacks() ) {
|
||||
settings.onChange.call(input);
|
||||
}
|
||||
},
|
||||
click: function(event) {
|
||||
var
|
||||
$target = $(event.target)
|
||||
;
|
||||
if( $target.is(selector.input) ) {
|
||||
module.verbose('Using default check action on initialized checkbox');
|
||||
return;
|
||||
}
|
||||
if( $target.is(selector.link) ) {
|
||||
module.debug('Clicking link inside checkbox, skipping toggle');
|
||||
return;
|
||||
}
|
||||
module.toggle();
|
||||
$input.focus();
|
||||
event.preventDefault();
|
||||
},
|
||||
keydown: function(event) {
|
||||
var
|
||||
key = event.which,
|
||||
keyCode = {
|
||||
enter : 13,
|
||||
space : 32,
|
||||
escape : 27,
|
||||
left : 37,
|
||||
up : 38,
|
||||
right : 39,
|
||||
down : 40
|
||||
}
|
||||
;
|
||||
|
||||
var r = module.get.radios(),
|
||||
rIndex = r.index($module),
|
||||
rLen = r.length,
|
||||
checkIndex = false;
|
||||
|
||||
if(key == keyCode.left || key == keyCode.up) {
|
||||
checkIndex = (rIndex === 0 ? rLen : rIndex) - 1;
|
||||
} else if(key == keyCode.right || key == keyCode.down) {
|
||||
checkIndex = rIndex === rLen-1 ? 0 : rIndex+1;
|
||||
}
|
||||
|
||||
if (!module.should.ignoreCallbacks() && checkIndex !== false) {
|
||||
if(settings.beforeUnchecked.apply(input)===false) {
|
||||
module.verbose('Option not allowed to be unchecked, cancelling key navigation');
|
||||
return false;
|
||||
}
|
||||
if (settings.beforeChecked.apply($(r[checkIndex]).children(selector.input)[0])===false) {
|
||||
module.verbose('Next option should not allow check, cancelling key navigation');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(key == keyCode.escape) {
|
||||
module.verbose('Escape key pressed blurring field');
|
||||
$input.blur();
|
||||
shortcutPressed = true;
|
||||
}
|
||||
else if(!event.ctrlKey && ( key == keyCode.space || (key == keyCode.enter && settings.enableEnterKey)) ) {
|
||||
module.verbose('Enter/space key pressed, toggling checkbox');
|
||||
module.toggle();
|
||||
shortcutPressed = true;
|
||||
}
|
||||
else {
|
||||
shortcutPressed = false;
|
||||
}
|
||||
},
|
||||
keyup: function(event) {
|
||||
if(shortcutPressed) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
check: function() {
|
||||
if( !module.should.allowCheck() ) {
|
||||
return;
|
||||
}
|
||||
module.debug('Checking checkbox', $input);
|
||||
module.set.checked();
|
||||
if( !module.should.ignoreCallbacks() ) {
|
||||
settings.onChecked.call(input);
|
||||
module.trigger.change();
|
||||
}
|
||||
module.preventDefaultOnInputTarget();
|
||||
},
|
||||
|
||||
uncheck: function() {
|
||||
if( !module.should.allowUncheck() ) {
|
||||
return;
|
||||
}
|
||||
module.debug('Unchecking checkbox');
|
||||
module.set.unchecked();
|
||||
if( !module.should.ignoreCallbacks() ) {
|
||||
settings.onUnchecked.call(input);
|
||||
module.trigger.change();
|
||||
}
|
||||
module.preventDefaultOnInputTarget();
|
||||
},
|
||||
|
||||
indeterminate: function() {
|
||||
if( module.should.allowIndeterminate() ) {
|
||||
module.debug('Checkbox is already indeterminate');
|
||||
return;
|
||||
}
|
||||
module.debug('Making checkbox indeterminate');
|
||||
module.set.indeterminate();
|
||||
if( !module.should.ignoreCallbacks() ) {
|
||||
settings.onIndeterminate.call(input);
|
||||
module.trigger.change();
|
||||
}
|
||||
},
|
||||
|
||||
determinate: function() {
|
||||
if( module.should.allowDeterminate() ) {
|
||||
module.debug('Checkbox is already determinate');
|
||||
return;
|
||||
}
|
||||
module.debug('Making checkbox determinate');
|
||||
module.set.determinate();
|
||||
if( !module.should.ignoreCallbacks() ) {
|
||||
settings.onDeterminate.call(input);
|
||||
module.trigger.change();
|
||||
}
|
||||
},
|
||||
|
||||
enable: function() {
|
||||
if( module.is.enabled() ) {
|
||||
module.debug('Checkbox is already enabled');
|
||||
return;
|
||||
}
|
||||
module.debug('Enabling checkbox');
|
||||
module.set.enabled();
|
||||
if( !module.should.ignoreCallbacks() ) {
|
||||
settings.onEnable.call(input);
|
||||
// preserve legacy callbacks
|
||||
settings.onEnabled.call(input);
|
||||
module.trigger.change();
|
||||
}
|
||||
},
|
||||
|
||||
disable: function() {
|
||||
if( module.is.disabled() ) {
|
||||
module.debug('Checkbox is already disabled');
|
||||
return;
|
||||
}
|
||||
module.debug('Disabling checkbox');
|
||||
module.set.disabled();
|
||||
if( !module.should.ignoreCallbacks() ) {
|
||||
settings.onDisable.call(input);
|
||||
// preserve legacy callbacks
|
||||
settings.onDisabled.call(input);
|
||||
module.trigger.change();
|
||||
}
|
||||
},
|
||||
|
||||
get: {
|
||||
radios: function() {
|
||||
var
|
||||
name = module.get.name()
|
||||
;
|
||||
return $('input[name="' + name + '"]').closest(selector.checkbox);
|
||||
},
|
||||
otherRadios: function() {
|
||||
return module.get.radios().not($module);
|
||||
},
|
||||
name: function() {
|
||||
return $input.attr('name');
|
||||
}
|
||||
},
|
||||
|
||||
is: {
|
||||
initialLoad: function() {
|
||||
return initialLoad;
|
||||
},
|
||||
radio: function() {
|
||||
return ($input.hasClass(className.radio) || $input.attr('type') == 'radio');
|
||||
},
|
||||
indeterminate: function() {
|
||||
return $input.prop('indeterminate') !== undefined && $input.prop('indeterminate');
|
||||
},
|
||||
checked: function() {
|
||||
return $input.prop('checked') !== undefined && $input.prop('checked');
|
||||
},
|
||||
disabled: function() {
|
||||
return $input.prop('disabled') !== undefined && $input.prop('disabled');
|
||||
},
|
||||
enabled: function() {
|
||||
return !module.is.disabled();
|
||||
},
|
||||
determinate: function() {
|
||||
return !module.is.indeterminate();
|
||||
},
|
||||
unchecked: function() {
|
||||
return !module.is.checked();
|
||||
}
|
||||
},
|
||||
|
||||
should: {
|
||||
allowCheck: function() {
|
||||
if(module.is.determinate() && module.is.checked() && !module.is.initialLoad() ) {
|
||||
module.debug('Should not allow check, checkbox is already checked');
|
||||
return false;
|
||||
}
|
||||
if(!module.should.ignoreCallbacks() && settings.beforeChecked.apply(input) === false) {
|
||||
module.debug('Should not allow check, beforeChecked cancelled');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
allowUncheck: function() {
|
||||
if(module.is.determinate() && module.is.unchecked() && !module.is.initialLoad() ) {
|
||||
module.debug('Should not allow uncheck, checkbox is already unchecked');
|
||||
return false;
|
||||
}
|
||||
if(!module.should.ignoreCallbacks() && settings.beforeUnchecked.apply(input) === false) {
|
||||
module.debug('Should not allow uncheck, beforeUnchecked cancelled');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
allowIndeterminate: function() {
|
||||
if(module.is.indeterminate() && !module.is.initialLoad() ) {
|
||||
module.debug('Should not allow indeterminate, checkbox is already indeterminate');
|
||||
return false;
|
||||
}
|
||||
if(!module.should.ignoreCallbacks() && settings.beforeIndeterminate.apply(input) === false) {
|
||||
module.debug('Should not allow indeterminate, beforeIndeterminate cancelled');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
allowDeterminate: function() {
|
||||
if(module.is.determinate() && !module.is.initialLoad() ) {
|
||||
module.debug('Should not allow determinate, checkbox is already determinate');
|
||||
return false;
|
||||
}
|
||||
if(!module.should.ignoreCallbacks() && settings.beforeDeterminate.apply(input) === false) {
|
||||
module.debug('Should not allow determinate, beforeDeterminate cancelled');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
ignoreCallbacks: function() {
|
||||
return (initialLoad && !settings.fireOnInit);
|
||||
}
|
||||
},
|
||||
|
||||
can: {
|
||||
change: function() {
|
||||
return !( $module.hasClass(className.disabled) || $module.hasClass(className.readOnly) || $input.prop('disabled') || $input.prop('readonly') );
|
||||
},
|
||||
uncheck: function() {
|
||||
return (typeof settings.uncheckable === 'boolean')
|
||||
? settings.uncheckable
|
||||
: !module.is.radio()
|
||||
;
|
||||
}
|
||||
},
|
||||
|
||||
set: {
|
||||
initialLoad: function() {
|
||||
initialLoad = true;
|
||||
},
|
||||
checked: function() {
|
||||
module.verbose('Setting class to checked');
|
||||
$module
|
||||
.removeClass(className.indeterminate)
|
||||
.addClass(className.checked)
|
||||
;
|
||||
if( module.is.radio() ) {
|
||||
module.uncheckOthers();
|
||||
}
|
||||
if(!module.is.indeterminate() && module.is.checked()) {
|
||||
module.debug('Input is already checked, skipping input property change');
|
||||
return;
|
||||
}
|
||||
module.verbose('Setting state to checked', input);
|
||||
$input
|
||||
.prop('indeterminate', false)
|
||||
.prop('checked', true)
|
||||
;
|
||||
},
|
||||
unchecked: function() {
|
||||
module.verbose('Removing checked class');
|
||||
$module
|
||||
.removeClass(className.indeterminate)
|
||||
.removeClass(className.checked)
|
||||
;
|
||||
if(!module.is.indeterminate() && module.is.unchecked() ) {
|
||||
module.debug('Input is already unchecked');
|
||||
return;
|
||||
}
|
||||
module.debug('Setting state to unchecked');
|
||||
$input
|
||||
.prop('indeterminate', false)
|
||||
.prop('checked', false)
|
||||
;
|
||||
},
|
||||
indeterminate: function() {
|
||||
module.verbose('Setting class to indeterminate');
|
||||
$module
|
||||
.addClass(className.indeterminate)
|
||||
;
|
||||
if( module.is.indeterminate() ) {
|
||||
module.debug('Input is already indeterminate, skipping input property change');
|
||||
return;
|
||||
}
|
||||
module.debug('Setting state to indeterminate');
|
||||
$input
|
||||
.prop('indeterminate', true)
|
||||
;
|
||||
},
|
||||
determinate: function() {
|
||||
module.verbose('Removing indeterminate class');
|
||||
$module
|
||||
.removeClass(className.indeterminate)
|
||||
;
|
||||
if( module.is.determinate() ) {
|
||||
module.debug('Input is already determinate, skipping input property change');
|
||||
return;
|
||||
}
|
||||
module.debug('Setting state to determinate');
|
||||
$input
|
||||
.prop('indeterminate', false)
|
||||
;
|
||||
},
|
||||
disabled: function() {
|
||||
module.verbose('Setting class to disabled');
|
||||
$module
|
||||
.addClass(className.disabled)
|
||||
;
|
||||
if( module.is.disabled() ) {
|
||||
module.debug('Input is already disabled, skipping input property change');
|
||||
return;
|
||||
}
|
||||
module.debug('Setting state to disabled');
|
||||
$input
|
||||
.prop('disabled', 'disabled')
|
||||
;
|
||||
},
|
||||
enabled: function() {
|
||||
module.verbose('Removing disabled class');
|
||||
$module.removeClass(className.disabled);
|
||||
if( module.is.enabled() ) {
|
||||
module.debug('Input is already enabled, skipping input property change');
|
||||
return;
|
||||
}
|
||||
module.debug('Setting state to enabled');
|
||||
$input
|
||||
.prop('disabled', false)
|
||||
;
|
||||
},
|
||||
tabbable: function() {
|
||||
module.verbose('Adding tabindex to checkbox');
|
||||
if( $input.attr('tabindex') === undefined) {
|
||||
$input.attr('tabindex', 0);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
remove: {
|
||||
initialLoad: function() {
|
||||
initialLoad = false;
|
||||
}
|
||||
},
|
||||
|
||||
trigger: {
|
||||
change: function() {
|
||||
var
|
||||
inputElement = $input[0]
|
||||
;
|
||||
if(inputElement) {
|
||||
var events = document.createEvent('HTMLEvents');
|
||||
module.verbose('Triggering native change event');
|
||||
events.initEvent('change', true, false);
|
||||
inputElement.dispatchEvent(events);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
create: {
|
||||
label: function() {
|
||||
if($input.prevAll(selector.label).length > 0) {
|
||||
$input.prev(selector.label).detach().insertAfter($input);
|
||||
module.debug('Moving existing label', $label);
|
||||
}
|
||||
else if( !module.has.label() ) {
|
||||
$label = $('<label>').insertAfter($input);
|
||||
module.debug('Creating label', $label);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
has: {
|
||||
label: function() {
|
||||
return ($label.length > 0);
|
||||
}
|
||||
},
|
||||
|
||||
bind: {
|
||||
events: function() {
|
||||
module.verbose('Attaching checkbox events');
|
||||
$module
|
||||
.on('click' + eventNamespace, module.event.click)
|
||||
.on('change' + eventNamespace, module.event.change)
|
||||
.on('keydown' + eventNamespace, selector.input, module.event.keydown)
|
||||
.on('keyup' + eventNamespace, selector.input, module.event.keyup)
|
||||
;
|
||||
}
|
||||
},
|
||||
|
||||
unbind: {
|
||||
events: function() {
|
||||
module.debug('Removing events');
|
||||
$module
|
||||
.off(eventNamespace)
|
||||
;
|
||||
}
|
||||
},
|
||||
|
||||
uncheckOthers: function() {
|
||||
var
|
||||
$radios = module.get.otherRadios()
|
||||
;
|
||||
module.debug('Unchecking other radios', $radios);
|
||||
$radios.removeClass(className.checked);
|
||||
},
|
||||
|
||||
toggle: function() {
|
||||
if( !module.can.change() ) {
|
||||
if(!module.is.radio()) {
|
||||
module.debug('Checkbox is read-only or disabled, ignoring toggle');
|
||||
}
|
||||
return;
|
||||
}
|
||||
if( module.is.indeterminate() || module.is.unchecked() ) {
|
||||
module.debug('Currently unchecked');
|
||||
module.check();
|
||||
}
|
||||
else if( module.is.checked() && module.can.uncheck() ) {
|
||||
module.debug('Currently checked');
|
||||
module.uncheck();
|
||||
}
|
||||
},
|
||||
setting: function(name, value) {
|
||||
module.debug('Changing setting', name, value);
|
||||
if( $.isPlainObject(name) ) {
|
||||
$.extend(true, settings, name);
|
||||
}
|
||||
else if(value !== undefined) {
|
||||
if($.isPlainObject(settings[name])) {
|
||||
$.extend(true, settings[name], value);
|
||||
}
|
||||
else {
|
||||
settings[name] = value;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return settings[name];
|
||||
}
|
||||
},
|
||||
internal: function(name, value) {
|
||||
if( $.isPlainObject(name) ) {
|
||||
$.extend(true, module, name);
|
||||
}
|
||||
else if(value !== undefined) {
|
||||
module[name] = value;
|
||||
}
|
||||
else {
|
||||
return module[name];
|
||||
}
|
||||
},
|
||||
debug: function() {
|
||||
if(!settings.silent && settings.debug) {
|
||||
if(settings.performance) {
|
||||
module.performance.log(arguments);
|
||||
}
|
||||
else {
|
||||
module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
|
||||
module.debug.apply(console, arguments);
|
||||
}
|
||||
}
|
||||
},
|
||||
verbose: function() {
|
||||
if(!settings.silent && settings.verbose && settings.debug) {
|
||||
if(settings.performance) {
|
||||
module.performance.log(arguments);
|
||||
}
|
||||
else {
|
||||
module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
|
||||
module.verbose.apply(console, arguments);
|
||||
}
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
if(!settings.silent) {
|
||||
module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
|
||||
module.error.apply(console, arguments);
|
||||
}
|
||||
},
|
||||
performance: {
|
||||
log: function(message) {
|
||||
var
|
||||
currentTime,
|
||||
executionTime,
|
||||
previousTime
|
||||
;
|
||||
if(settings.performance) {
|
||||
currentTime = new Date().getTime();
|
||||
previousTime = time || currentTime;
|
||||
executionTime = currentTime - previousTime;
|
||||
time = currentTime;
|
||||
performance.push({
|
||||
'Name' : message[0],
|
||||
'Arguments' : [].slice.call(message, 1) || '',
|
||||
'Element' : element,
|
||||
'Execution Time' : executionTime
|
||||
});
|
||||
}
|
||||
clearTimeout(module.performance.timer);
|
||||
module.performance.timer = setTimeout(module.performance.display, 500);
|
||||
},
|
||||
display: function() {
|
||||
var
|
||||
title = settings.name + ':',
|
||||
totalTime = 0
|
||||
;
|
||||
time = false;
|
||||
clearTimeout(module.performance.timer);
|
||||
$.each(performance, function(index, data) {
|
||||
totalTime += data['Execution Time'];
|
||||
});
|
||||
title += ' ' + totalTime + 'ms';
|
||||
if(moduleSelector) {
|
||||
title += ' \'' + moduleSelector + '\'';
|
||||
}
|
||||
if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
|
||||
console.groupCollapsed(title);
|
||||
if(console.table) {
|
||||
console.table(performance);
|
||||
}
|
||||
else {
|
||||
$.each(performance, function(index, data) {
|
||||
console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
|
||||
});
|
||||
}
|
||||
console.groupEnd();
|
||||
}
|
||||
performance = [];
|
||||
}
|
||||
},
|
||||
invoke: function(query, passedArguments, context) {
|
||||
var
|
||||
object = instance,
|
||||
maxDepth,
|
||||
found,
|
||||
response
|
||||
;
|
||||
passedArguments = passedArguments || queryArguments;
|
||||
context = element || context;
|
||||
if(typeof query == 'string' && object !== undefined) {
|
||||
query = query.split(/[\. ]/);
|
||||
maxDepth = query.length - 1;
|
||||
$.each(query, function(depth, value) {
|
||||
var camelCaseValue = (depth != maxDepth)
|
||||
? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
|
||||
: query
|
||||
;
|
||||
if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
|
||||
object = object[camelCaseValue];
|
||||
}
|
||||
else if( object[camelCaseValue] !== undefined ) {
|
||||
found = object[camelCaseValue];
|
||||
return false;
|
||||
}
|
||||
else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
|
||||
object = object[value];
|
||||
}
|
||||
else if( object[value] !== undefined ) {
|
||||
found = object[value];
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
module.error(error.method, query);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
if ( $.isFunction( found ) ) {
|
||||
response = found.apply(context, passedArguments);
|
||||
}
|
||||
else if(found !== undefined) {
|
||||
response = found;
|
||||
}
|
||||
if(Array.isArray(returnedValue)) {
|
||||
returnedValue.push(response);
|
||||
}
|
||||
else if(returnedValue !== undefined) {
|
||||
returnedValue = [returnedValue, response];
|
||||
}
|
||||
else if(response !== undefined) {
|
||||
returnedValue = response;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
};
|
||||
|
||||
if(methodInvoked) {
|
||||
if(instance === undefined) {
|
||||
module.initialize();
|
||||
}
|
||||
module.invoke(query);
|
||||
}
|
||||
else {
|
||||
if(instance !== undefined) {
|
||||
instance.invoke('destroy');
|
||||
}
|
||||
module.initialize();
|
||||
}
|
||||
})
|
||||
;
|
||||
|
||||
return (returnedValue !== undefined)
|
||||
? returnedValue
|
||||
: this
|
||||
;
|
||||
};
|
||||
|
||||
$.fn.checkbox.settings = {
|
||||
|
||||
name : 'Checkbox',
|
||||
namespace : 'checkbox',
|
||||
|
||||
silent : false,
|
||||
debug : false,
|
||||
verbose : true,
|
||||
performance : true,
|
||||
|
||||
// delegated event context
|
||||
uncheckable : 'auto',
|
||||
fireOnInit : false,
|
||||
enableEnterKey : true,
|
||||
|
||||
onChange : function(){},
|
||||
|
||||
beforeChecked : function(){},
|
||||
beforeUnchecked : function(){},
|
||||
beforeDeterminate : function(){},
|
||||
beforeIndeterminate : function(){},
|
||||
|
||||
onChecked : function(){},
|
||||
onUnchecked : function(){},
|
||||
|
||||
onDeterminate : function() {},
|
||||
onIndeterminate : function() {},
|
||||
|
||||
onEnable : function(){},
|
||||
onDisable : function(){},
|
||||
|
||||
// preserve misspelled callbacks (will be removed in 3.0)
|
||||
onEnabled : function(){},
|
||||
onDisabled : function(){},
|
||||
|
||||
className : {
|
||||
checked : 'checked',
|
||||
indeterminate : 'indeterminate',
|
||||
disabled : 'disabled',
|
||||
hidden : 'hidden',
|
||||
radio : 'radio',
|
||||
readOnly : 'read-only'
|
||||
},
|
||||
|
||||
error : {
|
||||
method : 'The method you called is not defined'
|
||||
},
|
||||
|
||||
selector : {
|
||||
checkbox : '.ui.checkbox',
|
||||
label : 'label, .box',
|
||||
input : 'input[type="checkbox"], input[type="radio"]',
|
||||
link : 'a[href]'
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
})( jQuery, window, document );
|
||||
|
||||
/*!
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
"components": [
|
||||
"api",
|
||||
"button",
|
||||
"checkbox",
|
||||
"dimmer",
|
||||
"dropdown",
|
||||
"form",
|
||||
|
|
|
@ -218,17 +218,24 @@ export function initAdminCommon() {
|
|||
});
|
||||
|
||||
// Select actions
|
||||
const $checkboxes = $('.select.table .ui.checkbox');
|
||||
const checkboxes = document.querySelectorAll('.select.table .ui.checkbox input');
|
||||
|
||||
$('.select.action').on('click', function () {
|
||||
switch ($(this).data('action')) {
|
||||
case 'select-all':
|
||||
$checkboxes.checkbox('check');
|
||||
for (const checkbox of checkboxes) {
|
||||
checkbox.checked = true;
|
||||
}
|
||||
break;
|
||||
case 'deselect-all':
|
||||
$checkboxes.checkbox('uncheck');
|
||||
for (const checkbox of checkboxes) {
|
||||
checkbox.checked = false;
|
||||
}
|
||||
break;
|
||||
case 'inverse':
|
||||
$checkboxes.checkbox('toggle');
|
||||
for (const checkbox of checkboxes) {
|
||||
checkbox.checked = !checkbox.checked;
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
@ -236,11 +243,11 @@ export function initAdminCommon() {
|
|||
e.preventDefault();
|
||||
this.classList.add('is-loading', 'disabled');
|
||||
const data = new FormData();
|
||||
$checkboxes.each(function () {
|
||||
if ($(this).checkbox('is checked')) {
|
||||
data.append('ids[]', this.getAttribute('data-id'));
|
||||
for (const checkbox of checkboxes) {
|
||||
if (checkbox.checked) {
|
||||
data.append('ids[]', checkbox.closest('.ui.checkbox').getAttribute('data-id'));
|
||||
}
|
||||
}
|
||||
});
|
||||
await POST(this.getAttribute('data-link'), {data});
|
||||
window.location.href = this.getAttribute('data-redirect');
|
||||
});
|
||||
|
|
|
@ -196,8 +196,6 @@ export function initGlobalCommon() {
|
|||
$uiDropdowns.filter('.upward').dropdown('setting', 'direction', 'upward');
|
||||
$uiDropdowns.filter('.downward').dropdown('setting', 'direction', 'downward');
|
||||
|
||||
$('.ui.checkbox').checkbox();
|
||||
|
||||
$('.tabular.menu .item').tab();
|
||||
|
||||
initSubmitEventPolyfill();
|
||||
|
|
|
@ -282,32 +282,26 @@ export function initRepoPullRequestMergeInstruction() {
|
|||
}
|
||||
|
||||
export function initRepoPullRequestAllowMaintainerEdit() {
|
||||
const checkbox = document.getElementById('allow-edits-from-maintainers');
|
||||
if (!checkbox) return;
|
||||
const wrapper = document.getElementById('allow-edits-from-maintainers');
|
||||
if (!wrapper) return;
|
||||
|
||||
const $checkbox = $(checkbox);
|
||||
|
||||
const promptError = checkbox.getAttribute('data-prompt-error');
|
||||
$checkbox.checkbox({
|
||||
'onChange': async () => {
|
||||
const checked = $checkbox.checkbox('is checked');
|
||||
let url = checkbox.getAttribute('data-url');
|
||||
url += '/set_allow_maintainer_edit';
|
||||
$checkbox.checkbox('set disabled');
|
||||
wrapper.querySelector('input[type="checkbox"]')?.addEventListener('change', async (e) => {
|
||||
const checked = e.target.checked;
|
||||
const url = `${wrapper.getAttribute('data-url')}/set_allow_maintainer_edit`;
|
||||
wrapper.classList.add('is-loading');
|
||||
e.target.disabled = true;
|
||||
try {
|
||||
const response = await POST(url, {
|
||||
data: {allow_maintainer_edit: checked},
|
||||
});
|
||||
const response = await POST(url, {data: {allow_maintainer_edit: checked}});
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to update maintainer edit permission');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
showTemporaryTooltip(checkbox, promptError);
|
||||
showTemporaryTooltip(wrapper, wrapper.getAttribute('data-prompt-error'));
|
||||
} finally {
|
||||
$checkbox.checkbox('set enabled');
|
||||
wrapper.classList.remove('is-loading');
|
||||
e.target.disabled = false;
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -11,8 +11,6 @@ export const fomanticMobileScreen = window.matchMedia('only screen and (max-widt
|
|||
export function initGiteaFomantic() {
|
||||
// Silence fomantic's error logging when tabs are used without a target content element
|
||||
$.fn.tab.settings.silent = true;
|
||||
// Disable the behavior of fomantic to toggle the checkbox when you press enter on a checkbox element.
|
||||
$.fn.checkbox.settings.enableEnterKey = false;
|
||||
|
||||
// By default, use "exact match" for full text search
|
||||
$.fn.dropdown.settings.fullTextSearch = 'exact';
|
||||
|
|
|
@ -41,24 +41,19 @@ The ideal checkboxes should be:
|
|||
<label><input type="checkbox"> ... </label>
|
||||
```
|
||||
|
||||
However, related CSS styles aren't supported (not implemented) yet, so at the moment,
|
||||
almost all the checkboxes are still using Fomantic UI checkbox.
|
||||
|
||||
## Fomantic UI Checkbox
|
||||
However, the templates still have the Fomantic-style HTML layout:
|
||||
|
||||
```html
|
||||
<div class="ui checkbox">
|
||||
<input type="checkbox"> <!-- class "hidden" will be added by $.checkbox() -->
|
||||
<input type="checkbox">
|
||||
<label>...</label>
|
||||
</div>
|
||||
```
|
||||
|
||||
Then the JS `$.checkbox()` should be called to make it work with keyboard and label-clicking,
|
||||
then it works like the ideal checkboxes.
|
||||
|
||||
There is still a problem: Fomantic UI checkbox is not friendly to screen readers,
|
||||
so we add IDs to all the Fomantic UI checkboxes automatically by JS.
|
||||
If the `label` part is empty, then the checkbox needs to get the `aria-label` attribute manually.
|
||||
We call `initAriaCheckboxPatch` to link the `input` and `label` which makes clicking the
|
||||
label etc. work. There is still a problem: These checkboxes are not friendly to screen readers,
|
||||
so we add IDs to all the Fomantic UI checkboxes automatically by JS. If the `label` part is empty,
|
||||
then the checkbox needs to get the `aria-label` attribute manually.
|
||||
|
||||
# Fomantic Dropdown
|
||||
|
||||
|
|
|
@ -1,38 +1,24 @@
|
|||
import $ from 'jquery';
|
||||
import {generateAriaId} from './base.js';
|
||||
|
||||
const ariaPatchKey = '_giteaAriaPatchCheckbox';
|
||||
const fomanticCheckboxFn = $.fn.checkbox;
|
||||
|
||||
// use our own `$.fn.checkbox` to patch Fomantic's checkbox module
|
||||
export function initAriaCheckboxPatch() {
|
||||
if ($.fn.checkbox === ariaCheckboxFn) throw new Error('initAriaCheckboxPatch could only be called once');
|
||||
$.fn.checkbox = ariaCheckboxFn;
|
||||
ariaCheckboxFn.settings = fomanticCheckboxFn.settings;
|
||||
}
|
||||
|
||||
// the patched `$.fn.checkbox` checkbox function
|
||||
// * it does the one-time attaching on the first call
|
||||
function ariaCheckboxFn(...args) {
|
||||
const ret = fomanticCheckboxFn.apply(this, args);
|
||||
for (const el of this) {
|
||||
if (el[ariaPatchKey]) continue;
|
||||
attachInit(el);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
function attachInit(el) {
|
||||
// Fomantic UI checkbox needs to be something like: <div class="ui checkbox"><label /><input /></div>
|
||||
// It doesn't work well with <label><input />...</label>
|
||||
// To make it work with aria, the "id"/"for" attributes are necessary, so add them automatically if missing.
|
||||
// In the future, refactor to use native checkbox directly, then this patch could be removed.
|
||||
el[ariaPatchKey] = {}; // record that this element has been patched
|
||||
// link the label and the input element so it's clickable and accessible
|
||||
for (const el of document.querySelectorAll('.ui.checkbox')) {
|
||||
if (el.hasAttribute('data-checkbox-patched')) continue;
|
||||
const label = el.querySelector('label');
|
||||
const input = el.querySelector('input');
|
||||
if (!label || !input || input.getAttribute('id')) return;
|
||||
if (!label || !input) continue;
|
||||
const inputId = input.getAttribute('id');
|
||||
const labelFor = label.getAttribute('for');
|
||||
|
||||
if (inputId && !labelFor) { // missing "for"
|
||||
label.setAttribute('for', inputId);
|
||||
} else if (!inputId && !labelFor) { // missing both "id" and "for"
|
||||
const id = generateAriaId();
|
||||
input.setAttribute('id', id);
|
||||
label.setAttribute('for', id);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
el.setAttribute('data-checkbox-patched', 'true');
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue