diff --git a/Dockerfile b/Dockerfile index 02e22e801d..ac8b4f1992 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.4 +FROM alpine:3.5 MAINTAINER Thomas Boerger EXPOSE 22 3000 diff --git a/Dockerfile.aarch64 b/Dockerfile.aarch64 index d9788ee739..34598332fc 100644 --- a/Dockerfile.aarch64 +++ b/Dockerfile.aarch64 @@ -1,4 +1,4 @@ -FROM aarch64/alpine:3.5 +FROM multiarch/alpine:aarch64-v3.5 EXPOSE 22 3000 diff --git a/Dockerfile.rpi b/Dockerfile.rpi index 3484b2e6e2..23b9f130b4 100644 --- a/Dockerfile.rpi +++ b/Dockerfile.rpi @@ -1,4 +1,4 @@ -FROM hypriot/rpi-alpine-scratch:v3.4 +FROM multiarch/alpine:armhf-v3.5 MAINTAINER Thomas Boerger EXPOSE 22 3000 diff --git a/Makefile b/Makefile index 48e782da0e..699273339f 100644 --- a/Makefile +++ b/Makefile @@ -140,7 +140,7 @@ release-windows: @hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ go get -u github.com/karalabe/xgo; \ fi - xgo -dest $(DIST)/binaries -tags '$(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) . + xgo -dest $(DIST)/binaries -tags 'netgo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) . ifeq ($(CI),drone) mv /build/* $(DIST)/binaries endif @@ -150,7 +150,7 @@ release-linux: @hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ go get -u github.com/karalabe/xgo; \ fi - xgo -dest $(DIST)/binaries -tags '$(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'linux/*' -out gitea-$(VERSION) . + xgo -dest $(DIST)/binaries -tags 'netgo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'linux/*' -out gitea-$(VERSION) . ifeq ($(CI),drone) mv /build/* $(DIST)/binaries endif @@ -160,7 +160,7 @@ release-darwin: @hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ go get -u github.com/karalabe/xgo; \ fi - xgo -dest $(DIST)/binaries -tags '$(TAGS)' -ldflags '$(LDFLAGS)' -targets 'darwin/*' -out gitea-$(VERSION) . + xgo -dest $(DIST)/binaries -tags 'netgo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'darwin/*' -out gitea-$(VERSION) . ifeq ($(CI),drone) mv /build/* $(DIST)/binaries endif diff --git a/cmd/serv.go b/cmd/serv.go index f7d025c68e..def19fc555 100644 --- a/cmd/serv.go +++ b/cmd/serv.go @@ -164,8 +164,6 @@ func runServ(c *cli.Context) error { fail("Internal error", "Failed to get repository owner (%s): %v", username, err) } - os.Setenv(models.EnvRepoUserSalt, repoUser.Salt) - repo, err := models.GetRepositoryByName(repoUser.ID, reponame) if err != nil { if models.IsErrRepoNotExist(err) { diff --git a/conf/app.ini b/conf/app.ini index b1eb953cdf..47fd4b1182 100644 --- a/conf/app.ini +++ b/conf/app.ini @@ -240,6 +240,9 @@ ENABLE_CAPTCHA = true ; Default value for KeepEmailPrivate ; New user will get the value of this setting copied into their profile DEFAULT_KEEP_EMAIL_PRIVATE = false +; Default value for AllowCreateOrganization +; New user will have rights set to create organizations depending on this setting +DEFAULT_ALLOW_CREATE_ORGANIZATION = true ; Default value for the domain part of the user's email address in the git log ; if he has set KeepEmailPrivate true. The user's email replaced with a ; concatenation of the user name in lower case, "@" and NO_REPLY_ADDRESS. diff --git a/integrations/html_helper.go b/integrations/html_helper.go index db4e2953e6..63f7340c5c 100644 --- a/integrations/html_helper.go +++ b/integrations/html_helper.go @@ -7,16 +7,15 @@ package integrations import ( "bytes" - "golang.org/x/net/html" + "github.com/PuerkitoBio/goquery" ) type HtmlDoc struct { - doc *html.Node - body *html.Node + doc *goquery.Document } func NewHtmlParser(content []byte) (*HtmlDoc, error) { - doc, err := html.Parse(bytes.NewReader(content)) + doc, err := goquery.NewDocumentFromReader(bytes.NewReader(content)) if err != nil { return nil, err } @@ -24,87 +23,12 @@ func NewHtmlParser(content []byte) (*HtmlDoc, error) { return &HtmlDoc{doc: doc}, nil } -func (doc *HtmlDoc) GetBody() *html.Node { - if doc.body == nil { - var b *html.Node - var f func(*html.Node) - f = func(n *html.Node) { - if n.Type == html.ElementNode && n.Data == "body" { - b = n - return - } - for c := n.FirstChild; c != nil; c = c.NextSibling { - f(c) - } - } - f(doc.doc) - if b != nil { - doc.body = b - } else { - doc.body = doc.doc - } - } - return doc.body -} - -func (doc *HtmlDoc) GetAttribute(n *html.Node, key string) (string, bool) { - for _, attr := range n.Attr { - if attr.Key == key { - return attr.Val, true - } - } - return "", false -} - -func (doc *HtmlDoc) checkAttr(n *html.Node, attr, val string) bool { - if n.Type == html.ElementNode { - s, ok := doc.GetAttribute(n, attr) - if ok && s == val { - return true - } - } - return false -} - -func (doc *HtmlDoc) traverse(n *html.Node, attr, val string) *html.Node { - if doc.checkAttr(n, attr, val) { - return n - } - - for c := n.FirstChild; c != nil; c = c.NextSibling { - result := doc.traverse(c, attr, val) - if result != nil { - return result - } - } - - return nil -} - -func (doc *HtmlDoc) GetElementById(id string) *html.Node { - return doc.traverse(doc.GetBody(), "id", id) -} - func (doc *HtmlDoc) GetInputValueById(id string) string { - inp := doc.GetElementById(id) - if inp == nil { - return "" - } - - val, _ := doc.GetAttribute(inp, "value") - return val -} - -func (doc *HtmlDoc) GetElementByName(name string) *html.Node { - return doc.traverse(doc.GetBody(), "name", name) + text, _ := doc.doc.Find("#" + id).Attr("value") + return text } func (doc *HtmlDoc) GetInputValueByName(name string) string { - inp := doc.GetElementByName(name) - if inp == nil { - return "" - } - - val, _ := doc.GetAttribute(inp, "value") - return val + text, _ := doc.doc.Find("input[name=\"" + name + "\"]").Attr("value") + return text } diff --git a/integrations/integration_test.go b/integrations/integration_test.go index 6696ff65fc..4a809403bd 100644 --- a/integrations/integration_test.go +++ b/integrations/integration_test.go @@ -94,11 +94,12 @@ func initIntegrationTest() { if err != nil { log.Fatalf("db.Query: %v", err) } - if rows.Next() { - break // database already exists - } - if _, err = db.Exec("CREATE DATABASE testgitea"); err != nil { - log.Fatalf("db.Exec: %v", err) + defer rows.Close() + + if !rows.Next() { + if _, err = db.Exec("CREATE DATABASE testgitea"); err != nil { + log.Fatalf("db.Exec: %v", err) + } } } routers.GlobalInit() diff --git a/integrations/internal_test.go b/integrations/internal_test.go new file mode 100644 index 0000000000..12d6fc8dc9 --- /dev/null +++ b/integrations/internal_test.go @@ -0,0 +1,45 @@ +// Copyright 2017 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package integrations + +import ( + "encoding/json" + "fmt" + "net/http" + "net/url" + "testing" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/setting" + + "github.com/stretchr/testify/assert" +) + +func assertProtectedBranch(t *testing.T, repoID int64, branchName string, isErr, canPush bool) { + reqURL := fmt.Sprintf("/api/internal/branch/%d/%s", repoID, url.QueryEscape(branchName)) + req, err := http.NewRequest("GET", reqURL, nil) + t.Log(reqURL) + req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", setting.InternalToken)) + + assert.NoError(t, err) + resp := MakeRequest(req) + if isErr { + assert.EqualValues(t, 500, resp.HeaderCode) + } else { + assert.EqualValues(t, http.StatusOK, resp.HeaderCode) + var branch models.ProtectedBranch + t.Log(string(resp.Body)) + assert.NoError(t, json.Unmarshal(resp.Body, &branch)) + assert.Equal(t, canPush, branch.CanPush) + } +} + +func TestInternal_GetProtectedBranch(t *testing.T) { + prepareTestEnv(t) + + assertProtectedBranch(t, 1, "master", false, true) + assertProtectedBranch(t, 1, "dev", false, true) + assertProtectedBranch(t, 1, "lunny/dev", false, true) +} diff --git a/integrations/mysql.ini b/integrations/mysql.ini index b15588c867..9560b4ff9f 100644 --- a/integrations/mysql.ini +++ b/integrations/mysql.ini @@ -32,6 +32,7 @@ DISABLE_REGISTRATION = false ENABLE_CAPTCHA = false REQUIRE_SIGNIN_VIEW = false DEFAULT_KEEP_EMAIL_PRIVATE = false +DEFAULT_ALLOW_CREATE_ORGANIZATION = true NO_REPLY_ADDRESS = noreply.example.org [picture] diff --git a/integrations/pgsql.ini b/integrations/pgsql.ini index 920a5190d4..a0cae0dabc 100644 --- a/integrations/pgsql.ini +++ b/integrations/pgsql.ini @@ -32,6 +32,7 @@ DISABLE_REGISTRATION = false ENABLE_CAPTCHA = false REQUIRE_SIGNIN_VIEW = false DEFAULT_KEEP_EMAIL_PRIVATE = false +DEFAULT_ALLOW_CREATE_ORGANIZATION = true NO_REPLY_ADDRESS = noreply.example.org [picture] diff --git a/integrations/repo_commits_test.go b/integrations/repo_commits_test.go new file mode 100644 index 0000000000..9be9b78e53 --- /dev/null +++ b/integrations/repo_commits_test.go @@ -0,0 +1,94 @@ +// Copyright 2017 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package integrations + +import ( + "bytes" + "net/http" + "path" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestRepoCommits(t *testing.T) { + prepareTestEnv(t) + + session := loginUser(t, "user2", "password") + + // Request repository commits page + req, err := http.NewRequest("GET", "/user2/repo1/commits/master", nil) + assert.NoError(t, err) + resp := session.MakeRequest(t, req) + assert.EqualValues(t, http.StatusOK, resp.HeaderCode) + + doc, err := NewHtmlParser(resp.Body) + assert.NoError(t, err) + commitURL, exists := doc.doc.Find("#commits-table tbody tr td.sha a").Attr("href") + assert.True(t, exists) + assert.NotEmpty(t, commitURL) +} + +func doTestRepoCommitWithStatus(t *testing.T, state string, classes ...string) { + prepareTestEnv(t) + + session := loginUser(t, "user2", "password") + + // Request repository commits page + req, err := http.NewRequest("GET", "/user2/repo1/commits/master", nil) + assert.NoError(t, err) + resp := session.MakeRequest(t, req) + assert.EqualValues(t, http.StatusOK, resp.HeaderCode) + + doc, err := NewHtmlParser(resp.Body) + assert.NoError(t, err) + // Get first commit URL + commitURL, exists := doc.doc.Find("#commits-table tbody tr td.sha a").Attr("href") + assert.True(t, exists) + assert.NotEmpty(t, commitURL) + + // Call API to add status for commit + req, err = http.NewRequest("POST", "/api/v1/repos/user2/repo1/statuses/"+path.Base(commitURL), + bytes.NewBufferString("{\"state\":\""+state+"\", \"target_url\": \"http://test.ci/\", \"description\": \"\", \"context\": \"testci\"}")) + + assert.NoError(t, err) + req.Header.Add("Content-Type", "application/json") + resp = session.MakeRequest(t, req) + assert.EqualValues(t, http.StatusCreated, resp.HeaderCode) + + req, err = http.NewRequest("GET", "/user2/repo1/commits/master", nil) + assert.NoError(t, err) + resp = session.MakeRequest(t, req) + assert.EqualValues(t, http.StatusOK, resp.HeaderCode) + + doc, err = NewHtmlParser(resp.Body) + assert.NoError(t, err) + // Check if commit status is displayed in message column + sel := doc.doc.Find("#commits-table tbody tr td.message i.commit-status") + assert.Equal(t, sel.Length(), 1) + for _, class := range classes { + assert.True(t, sel.HasClass(class)) + } +} + +func TestRepoCommitsWithStatusPending(t *testing.T) { + doTestRepoCommitWithStatus(t, "pending", "circle", "yellow") +} + +func TestRepoCommitsWithStatusSuccess(t *testing.T) { + doTestRepoCommitWithStatus(t, "success", "check", "green") +} + +func TestRepoCommitsWithStatusError(t *testing.T) { + doTestRepoCommitWithStatus(t, "error", "warning", "red") +} + +func TestRepoCommitsWithStatusFailure(t *testing.T) { + doTestRepoCommitWithStatus(t, "failure", "remove", "red") +} + +func TestRepoCommitsWithStatusWarning(t *testing.T) { + doTestRepoCommitWithStatus(t, "warning", "warning", "sign", "yellow") +} diff --git a/integrations/sqlite.ini b/integrations/sqlite.ini index dc17b23ec8..9ced8c025b 100644 --- a/integrations/sqlite.ini +++ b/integrations/sqlite.ini @@ -32,6 +32,7 @@ DISABLE_REGISTRATION = false ENABLE_CAPTCHA = false REQUIRE_SIGNIN_VIEW = false DEFAULT_KEEP_EMAIL_PRIVATE = false +DEFAULT_ALLOW_CREATE_ORGANIZATION = true NO_REPLY_ADDRESS = noreply.example.org [picture] diff --git a/models/pull.go b/models/pull.go index 07c58446da..aba1046402 100644 --- a/models/pull.go +++ b/models/pull.go @@ -1058,29 +1058,30 @@ func (pr *PullRequest) checkAndUpdateStatus() { // TODO: test more pull requests at same time. func TestPullRequests() { prs := make([]*PullRequest, 0, 10) - x.Iterate(PullRequest{ - Status: PullRequestStatusChecking, - }, - func(idx int, bean interface{}) error { - pr := bean.(*PullRequest) - - if err := pr.GetBaseRepo(); err != nil { - log.Error(3, "GetBaseRepo: %v", err) - return nil - } - if pr.manuallyMerged() { - return nil - } - if err := pr.testPatch(); err != nil { - log.Error(3, "testPatch: %v", err) - return nil - } - prs = append(prs, pr) - return nil - }) + + err := x.Where("status = ?", PullRequestStatusChecking).Find(&prs) + if err != nil { + log.Error(3, "Find Checking PRs", err) + return + } + + var checkedPRs = make(map[int64]struct{}) // Update pull request status. for _, pr := range prs { + checkedPRs[pr.ID] = struct{}{} + if err := pr.GetBaseRepo(); err != nil { + log.Error(3, "GetBaseRepo: %v", err) + continue + } + if pr.manuallyMerged() { + continue + } + if err := pr.testPatch(); err != nil { + log.Error(3, "testPatch: %v", err) + continue + } + pr.checkAndUpdateStatus() } @@ -1089,7 +1090,12 @@ func TestPullRequests() { log.Trace("TestPullRequests[%v]: processing test task", prID) pullRequestQueue.Remove(prID) - pr, err := GetPullRequestByID(com.StrTo(prID).MustInt64()) + id := com.StrTo(prID).MustInt64() + if _, ok := checkedPRs[id]; ok { + continue + } + + pr, err := GetPullRequestByID(id) if err != nil { log.Error(4, "GetPullRequestByID[%s]: %v", prID, err) continue diff --git a/models/repo.go b/models/repo.go index 0a195e7be9..bc69a1e5f0 100644 --- a/models/repo.go +++ b/models/repo.go @@ -286,6 +286,8 @@ func (repo *Repository) APIFormat(mode AccessMode) *api.Repository { FullName: repo.FullName(), Description: repo.Description, Private: repo.IsPrivate, + Empty: repo.IsBare, + Size: int(repo.Size/1024), Fork: repo.IsFork, Mirror: repo.IsMirror, HTMLURL: repo.HTMLURL(), diff --git a/models/repo_list.go b/models/repo_list.go index 0c27281f17..a2dae85c84 100644 --- a/models/repo_list.go +++ b/models/repo_list.go @@ -115,9 +115,6 @@ func SearchRepositoryByName(opts *SearchRepoOptions) (repos RepositoryList, coun cond = builder.NewCond() ) - if len(opts.Keyword) == 0 { - return repos, 0, nil - } opts.Keyword = strings.ToLower(opts.Keyword) if opts.Page <= 0 { diff --git a/models/status.go b/models/status.go index 2e44ed93e6..2ce588bea5 100644 --- a/models/status.go +++ b/models/status.go @@ -5,6 +5,7 @@ package models import ( + "container/list" "fmt" "strings" "time" @@ -144,10 +145,20 @@ func GetCommitStatuses(repo *Repository, sha string, page int) ([]*CommitStatus, // GetLatestCommitStatus returns all statuses with a unique context for a given commit. func GetLatestCommitStatus(repo *Repository, sha string, page int) ([]*CommitStatus, error) { - statuses := make([]*CommitStatus, 0, 10) - return statuses, x.Limit(10, page*10). - Where("repo_id = ?", repo.ID).And("sha = ?", sha).Select("*"). - GroupBy("context").Desc("created_unix").Find(&statuses) + ids := make([]int64, 0, 10) + err := x.Limit(10, page*10). + Table(&CommitStatus{}). + Where("repo_id = ?", repo.ID).And("sha = ?", sha). + Select("max( id ) as id"). + GroupBy("context").OrderBy("max( id ) desc").Find(&ids) + if err != nil { + return nil, err + } + statuses := make([]*CommitStatus, 0, len(ids)) + if len(ids) == 0 { + return statuses, nil + } + return statuses, x.In("id", ids).Find(&statuses) } // GetCommitStatus populates a given status for a given commit. @@ -252,3 +263,42 @@ func NewCommitStatus(repo *Repository, creator *User, sha string, status *Commit return sess.Commit() } + +// SignCommitWithStatuses represents a commit with validation of signature and status state. +type SignCommitWithStatuses struct { + Statuses []*CommitStatus + State CommitStatusState + *SignCommit +} + +// ParseCommitsWithStatus checks commits latest statuses and calculates its worst status state +func ParseCommitsWithStatus(oldCommits *list.List, repo *Repository) *list.List { + var ( + newCommits = list.New() + e = oldCommits.Front() + err error + ) + + for e != nil { + c := e.Value.(SignCommit) + commit := SignCommitWithStatuses{ + SignCommit: &c, + State: "", + Statuses: make([]*CommitStatus, 0), + } + commit.Statuses, err = GetLatestCommitStatus(repo, commit.ID.String(), 0) + if err != nil { + log.Error(3, "GetLatestCommitStatus: %v", err) + } else { + for _, status := range commit.Statuses { + if status.State.IsWorseThan(commit.State) { + commit.State = status.State + } + } + } + + newCommits.PushBack(commit) + e = e.Next() + } + return newCommits +} diff --git a/models/update.go b/models/update.go index 7ee00f2c27..cd22189f6a 100644 --- a/models/update.go +++ b/models/update.go @@ -19,7 +19,6 @@ import ( const ( EnvRepoName = "GITEA_REPO_NAME" EnvRepoUsername = "GITEA_REPO_USER_NAME" - EnvRepoUserSalt = "GITEA_REPO_USER_SALT" EnvRepoIsWiki = "GITEA_REPO_IS_WIKI" EnvPusherName = "GITEA_PUSHER_NAME" EnvPusherID = "GITEA_PUSHER_ID" diff --git a/models/user.go b/models/user.go index 6cab6eaa6c..a42ba6f90f 100644 --- a/models/user.go +++ b/models/user.go @@ -706,7 +706,7 @@ func CreateUser(u *User) (err error) { return err } u.EncodePasswd() - u.AllowCreateOrganization = true + u.AllowCreateOrganization = setting.Service.DefaultAllowCreateOrganization u.MaxRepoCreation = -1 sess := x.NewSession() diff --git a/models/webhook.go b/models/webhook.go index 8cd2b7dd43..3fb1e57e78 100644 --- a/models/webhook.go +++ b/models/webhook.go @@ -612,18 +612,16 @@ func (t *HookTask) deliver() { // TODO: shoot more hooks at same time. func DeliverHooks() { tasks := make([]*HookTask, 0, 10) - x. - Where("is_delivered=?", false). - Iterate(new(HookTask), - func(idx int, bean interface{}) error { - t := bean.(*HookTask) - t.deliver() - tasks = append(tasks, t) - return nil - }) + err := x.Where("is_delivered=?", false).Find(&tasks) + if err != nil { + log.Error(4, "DeliverHooks: %v", err) + return + } // Update hook task status. for _, t := range tasks { + t.deliver() + if err := UpdateHookTask(t); err != nil { log.Error(4, "UpdateHookTask [%d]: %v", t.ID, err) } diff --git a/modules/auth/user_form.go b/modules/auth/user_form.go index 9e19c78a45..ea6e464a7f 100644 --- a/modules/auth/user_form.go +++ b/modules/auth/user_form.go @@ -45,6 +45,7 @@ type InstallForm struct { EnableCaptcha bool RequireSignInView bool DefaultKeepEmailPrivate bool + DefaultAllowCreateOrganization bool NoReplyAddress string AdminName string `binding:"OmitEmpty;AlphaDashDot;MaxSize(30)" locale:"install.admin_name"` diff --git a/modules/markdown/markdown.go b/modules/markdown/markdown.go index a469f98ba7..865ac6de6b 100644 --- a/modules/markdown/markdown.go +++ b/modules/markdown/markdown.go @@ -56,7 +56,7 @@ var ( // Sha1CurrentPattern matches string that represents a commit SHA, e.g. d8a994ef243349f321568f9e36d5c3f444b99cae // FIXME: this pattern matches pure numbers as well, right now we do a hack to check in renderSha1CurrentPattern // by converting string to a number. - Sha1CurrentPattern = regexp.MustCompile(`(?:^|\s|\()[0-9a-f]{40}\b`) + Sha1CurrentPattern = regexp.MustCompile(`(?:^|\s|\()([0-9a-f]{40})\b`) // ShortLinkPattern matches short but difficult to parse [[name|link|arg=test]] syntax ShortLinkPattern = regexp.MustCompile(`(\[\[.*\]\]\w*)`) @@ -542,12 +542,12 @@ func RenderCrossReferenceIssueIndexPattern(rawBytes []byte, urlPrefix string, me func renderSha1CurrentPattern(rawBytes []byte, urlPrefix string) []byte { ms := Sha1CurrentPattern.FindAllSubmatch(rawBytes, -1) for _, m := range ms { - all := m[0] - if com.StrTo(all).MustInt() > 0 { + hash := m[1] + if com.StrTo(hash).MustInt() > 0 { continue } - rawBytes = bytes.Replace(rawBytes, all, []byte(fmt.Sprintf( - `%s`, URLJoin(urlPrefix, "commit", string(all)), base.ShortSha(string(all)))), -1) + rawBytes = bytes.Replace(rawBytes, hash, []byte(fmt.Sprintf( + `%s`, URLJoin(urlPrefix, "commit", string(hash)), base.ShortSha(string(hash)))), -1) } return rawBytes } diff --git a/modules/markdown/markdown_test.go b/modules/markdown/markdown_test.go index 8364146573..e6bc3683c6 100644 --- a/modules/markdown/markdown_test.go +++ b/modules/markdown/markdown_test.go @@ -296,6 +296,7 @@ func TestRender_Commits(t *testing.T) { test(sha, `

b6dd6210ea

`) test(commit, `

b6dd6210ea

`) test(tree, `

b6dd6210ea/src

`) + test("commit "+sha, `

commit b6dd6210ea

`) } func TestRender_Images(t *testing.T) { diff --git a/modules/setting/setting.go b/modules/setting/setting.go index c21bbb4aa5..9f6f43e602 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -977,6 +977,7 @@ var Service struct { EnableReverseProxyAutoRegister bool EnableCaptcha bool DefaultKeepEmailPrivate bool + DefaultAllowCreateOrganization bool NoReplyAddress string // OpenID settings @@ -997,6 +998,7 @@ func newService() { Service.EnableReverseProxyAutoRegister = sec.Key("ENABLE_REVERSE_PROXY_AUTO_REGISTRATION").MustBool() Service.EnableCaptcha = sec.Key("ENABLE_CAPTCHA").MustBool() Service.DefaultKeepEmailPrivate = sec.Key("DEFAULT_KEEP_EMAIL_PRIVATE").MustBool() + Service.DefaultAllowCreateOrganization = sec.Key("DEFAULT_ALLOW_CREATE_ORGANIZATION").MustBool(true) Service.NoReplyAddress = sec.Key("NO_REPLY_ADDRESS").MustString("noreply.example.org") sec = Cfg.Section("openid") diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 31fd176b02..5831f02476 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -132,6 +132,8 @@ install_success = Welcome! We're glad that you chose Gitea, have fun and take ca invalid_log_root_path = Log root path is invalid: %v default_keep_email_private = Default Value for Keep Email Private default_keep_email_private_popup = This is the default value for the visibility of the user's email address. If set to true the email address of all new users will be hidden until the user changes his setting. +default_allow_create_organization = Default permission value for new users to create Organizations +default_allow_create_organization_popup = This is default permission value that will be assigned for new users. If set to true new users will be allowed to create Organizations. no_reply_address = No-reply Address no_reply_address_helper = Domain for the user's email address in git logs if he keeps his email address private. E.g. user 'joe' and 'noreply.example.org' will be 'joe@noreply.example.org' @@ -1268,6 +1270,7 @@ config.enable_captcha = Enable Captcha config.active_code_lives = Active Code Lives config.reset_password_code_lives = Reset Password Code Lives config.default_keep_email_private = Default Value for Keep Email Private +config.default_allow_create_organization = Default permission to create Organizations config.no_reply_address = No-reply Address config.webhook_config = Webhook Configuration diff --git a/public/assets/octicons-4.3.0/octicons.eot b/public/assets/octicons-4.3.0/octicons.eot old mode 100755 new mode 100644 diff --git a/public/assets/octicons-4.3.0/octicons.min.css b/public/assets/octicons-4.3.0/octicons.min.css old mode 100755 new mode 100644 diff --git a/public/assets/octicons-4.3.0/octicons.svg b/public/assets/octicons-4.3.0/octicons.svg old mode 100755 new mode 100644 diff --git a/public/assets/octicons-4.3.0/octicons.ttf b/public/assets/octicons-4.3.0/octicons.ttf old mode 100755 new mode 100644 diff --git a/public/assets/octicons-4.3.0/octicons.woff b/public/assets/octicons-4.3.0/octicons.woff old mode 100755 new mode 100644 diff --git a/public/assets/octicons-4.3.0/octicons.woff2 b/public/assets/octicons-4.3.0/octicons.woff2 old mode 100755 new mode 100644 diff --git a/public/css/index.css b/public/css/index.css index 5d3a73c9a5..f70793c8b2 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -1312,6 +1312,9 @@ footer .ui.language .menu { padding-top: 8px; padding-bottom: 8px; } +.repository.file.list #repo-files-table td.message .isSigned { + cursor: default; +} .repository.file.list #repo-files-table tr:hover { background-color: #ffffEE; } @@ -1939,10 +1942,15 @@ footer .ui.language .menu { .repository #commits-table td.sha .sha.label { margin: 0; } -.repository #commits-table td.sha .sha.label.isSigned { +.repository #commits-table.ui.basic.striped.table tbody tr:nth-child(2n) { + background-color: rgba(0, 0, 0, 0.02) !important; +} +.repository #commits-table td.sha .sha.label.isSigned, +.repository #repo-files-table .sha.label.isSigned { border: 1px solid #BBB; } -.repository #commits-table td.sha .sha.label.isSigned .detail.icon { +.repository #commits-table td.sha .sha.label.isSigned .detail.icon, +.repository #repo-files-table .sha.label.isSigned .detail.icon { background: #FAFAFA; margin: -6px -10px -4px 0px; padding: 5px 3px 5px 6px; @@ -1950,16 +1958,15 @@ footer .ui.language .menu { border-top-left-radius: 0; border-bottom-left-radius: 0; } -.repository #commits-table td.sha .sha.label.isSigned.isVerified { +.repository #commits-table td.sha .sha.label.isSigned.isVerified, +.repository #repo-files-table .sha.label.isSigned.isVerified { border: 1px solid #21BA45; background: #21BA4518; } -.repository #commits-table td.sha .sha.label.isSigned.isVerified .detail.icon { +.repository #commits-table td.sha .sha.label.isSigned.isVerified .detail.icon, +.repository #repo-files-table .sha.label.isSigned.isVerified .detail.icon { border-left: 1px solid #21BA4580; } -.repository #commits-table.ui.basic.striped.table tbody tr:nth-child(2n) { - background-color: rgba(0, 0, 0, 0.02) !important; -} .repository .diff-detail-box { margin: 15px 0; line-height: 30px; @@ -2982,12 +2989,12 @@ table[data-table-type="yaml-metadata"] { margin: 0; } .admin dl.admin-dl-horizontal dd { - margin-left: 240px; + margin-left: 275px; } .admin dl.admin-dl-horizontal dt { font-weight: bolder; float: left; - width: 250px; + width: 285px; clear: left; overflow: hidden; text-overflow: ellipsis; diff --git a/public/css/semantic-2.2.1.min.css b/public/css/semantic-2.2.1.min.css old mode 100755 new mode 100644 diff --git a/public/css/themes/basic/assets/fonts/icons.eot b/public/css/themes/basic/assets/fonts/icons.eot old mode 100755 new mode 100644 diff --git a/public/css/themes/basic/assets/fonts/icons.svg b/public/css/themes/basic/assets/fonts/icons.svg old mode 100755 new mode 100644 diff --git a/public/css/themes/basic/assets/fonts/icons.ttf b/public/css/themes/basic/assets/fonts/icons.ttf old mode 100755 new mode 100644 diff --git a/public/css/themes/basic/assets/fonts/icons.woff b/public/css/themes/basic/assets/fonts/icons.woff old mode 100755 new mode 100644 diff --git a/public/css/themes/default/assets/fonts/icons.eot b/public/css/themes/default/assets/fonts/icons.eot old mode 100755 new mode 100644 diff --git a/public/css/themes/default/assets/fonts/icons.otf b/public/css/themes/default/assets/fonts/icons.otf old mode 100755 new mode 100644 diff --git a/public/css/themes/default/assets/fonts/icons.svg b/public/css/themes/default/assets/fonts/icons.svg old mode 100755 new mode 100644 diff --git a/public/css/themes/default/assets/fonts/icons.ttf b/public/css/themes/default/assets/fonts/icons.ttf old mode 100755 new mode 100644 diff --git a/public/css/themes/default/assets/fonts/icons.woff b/public/css/themes/default/assets/fonts/icons.woff old mode 100755 new mode 100644 diff --git a/public/css/themes/default/assets/fonts/icons.woff2 b/public/css/themes/default/assets/fonts/icons.woff2 old mode 100755 new mode 100644 diff --git a/public/css/themes/default/assets/images/flags.png b/public/css/themes/default/assets/images/flags.png old mode 100755 new mode 100644 diff --git a/public/css/themes/github/assets/fonts/octicons-local.ttf b/public/css/themes/github/assets/fonts/octicons-local.ttf old mode 100755 new mode 100644 diff --git a/public/css/themes/github/assets/fonts/octicons.svg b/public/css/themes/github/assets/fonts/octicons.svg old mode 100755 new mode 100644 diff --git a/public/css/themes/github/assets/fonts/octicons.ttf b/public/css/themes/github/assets/fonts/octicons.ttf old mode 100755 new mode 100644 diff --git a/public/css/themes/github/assets/fonts/octicons.woff b/public/css/themes/github/assets/fonts/octicons.woff old mode 100755 new mode 100644 diff --git a/public/js/index.js b/public/js/index.js index 654831333f..804f3357c3 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -1560,6 +1560,7 @@ $(document).ready(function () { initWebhook(); initAdmin(); initCodeView(); + initDashboardSearch(); // Repo clone url. if ($('#repo-clone-url').length > 0) { @@ -1635,13 +1636,6 @@ $(function () { if ($('.user.signin').length > 0) return; $('form').areYouSure(); - $("#search_repo").on('change paste keyup',function(){ - var value = $(this).val(); - $.map($('.search-list li'), function(i) { - $(i).css("display", (value.trim().length == 0 || $(i).attr("data-title").trim().toLowerCase().indexOf(value.trim().toLowerCase()) > -1) ? "" : "none"); - }); - }); - // Parse SSH Key $("#ssh-key-content").on('change paste keyup',function(){ var arrays = $(this).val().split(" "); @@ -1651,3 +1645,64 @@ $(function () { } }); }); + +function initDashboardSearch() { + var el = document.getElementById('dashboard-repo-search'); + if (!el) { + return; + } + + new Vue({ + delimiters: ['<%', '%>'], + el: el, + + data: { + tab: 'repos', + repos: [], + searchQuery: '', + suburl: document.querySelector('meta[name=_suburl]').content, + uid: document.querySelector('meta[name=_uid]').content + }, + + mounted: function() { + this.searchRepos(); + + Vue.nextTick(function() { + document.querySelector('#search_repo').focus(); + }); + }, + + methods: { + changeTab: function(t) { + this.tab = t; + }, + + searchKeyUp: function() { + this.searchRepos(); + }, + + searchRepos: function() { + var self = this; + $.getJSON(this.searchURL(), function(result) { + self.repos = result.data; + }); + }, + + searchURL: function() { + return this.suburl + '/api/v1/repos/search?uid=' + this.uid + '&q=' + this.searchQuery; + }, + + repoClass: function(repo) { + if (repo.fork) { + return 'octicon octicon-repo-forked'; + } else if (repo.mirror) { + return 'octicon octicon-repo-clone'; + } else if (repo.private) { + return 'octicon octicon-repo-forked'; + } else { + return 'octicon octicon-repo'; + } + } + } + }); +} diff --git a/public/js/libs/clipboard-1.5.9.min.js b/public/js/libs/clipboard-1.5.9.min.js old mode 100755 new mode 100644 diff --git a/public/js/libs/vue.js b/public/js/libs/vue.js new file mode 100644 index 0000000000..918e77919c --- /dev/null +++ b/public/js/libs/vue.js @@ -0,0 +1,8568 @@ +/*! + * Vue.js v2.1.10 + * (c) 2014-2017 Evan You + * Released under the MIT License. + */ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global.Vue = factory()); +}(this, (function () { 'use strict'; + +/* */ + +/** + * Convert a value to a string that is actually rendered. + */ +function _toString (val) { + return val == null + ? '' + : typeof val === 'object' + ? JSON.stringify(val, null, 2) + : String(val) +} + +/** + * Convert a input value to a number for persistence. + * If the conversion fails, return original string. + */ +function toNumber (val) { + var n = parseFloat(val); + return isNaN(n) ? val : n +} + +/** + * Make a map and return a function for checking if a key + * is in that map. + */ +function makeMap ( + str, + expectsLowerCase +) { + var map = Object.create(null); + var list = str.split(','); + for (var i = 0; i < list.length; i++) { + map[list[i]] = true; + } + return expectsLowerCase + ? function (val) { return map[val.toLowerCase()]; } + : function (val) { return map[val]; } +} + +/** + * Check if a tag is a built-in tag. + */ +var isBuiltInTag = makeMap('slot,component', true); + +/** + * Remove an item from an array + */ +function remove$1 (arr, item) { + if (arr.length) { + var index = arr.indexOf(item); + if (index > -1) { + return arr.splice(index, 1) + } + } +} + +/** + * Check whether the object has the property. + */ +var hasOwnProperty = Object.prototype.hasOwnProperty; +function hasOwn (obj, key) { + return hasOwnProperty.call(obj, key) +} + +/** + * Check if value is primitive + */ +function isPrimitive (value) { + return typeof value === 'string' || typeof value === 'number' +} + +/** + * Create a cached version of a pure function. + */ +function cached (fn) { + var cache = Object.create(null); + return (function cachedFn (str) { + var hit = cache[str]; + return hit || (cache[str] = fn(str)) + }) +} + +/** + * Camelize a hyphen-delimited string. + */ +var camelizeRE = /-(\w)/g; +var camelize = cached(function (str) { + return str.replace(camelizeRE, function (_, c) { return c ? c.toUpperCase() : ''; }) +}); + +/** + * Capitalize a string. + */ +var capitalize = cached(function (str) { + return str.charAt(0).toUpperCase() + str.slice(1) +}); + +/** + * Hyphenate a camelCase string. + */ +var hyphenateRE = /([^-])([A-Z])/g; +var hyphenate = cached(function (str) { + return str + .replace(hyphenateRE, '$1-$2') + .replace(hyphenateRE, '$1-$2') + .toLowerCase() +}); + +/** + * Simple bind, faster than native + */ +function bind$1 (fn, ctx) { + function boundFn (a) { + var l = arguments.length; + return l + ? l > 1 + ? fn.apply(ctx, arguments) + : fn.call(ctx, a) + : fn.call(ctx) + } + // record original fn length + boundFn._length = fn.length; + return boundFn +} + +/** + * Convert an Array-like object to a real Array. + */ +function toArray (list, start) { + start = start || 0; + var i = list.length - start; + var ret = new Array(i); + while (i--) { + ret[i] = list[i + start]; + } + return ret +} + +/** + * Mix properties into target object. + */ +function extend (to, _from) { + for (var key in _from) { + to[key] = _from[key]; + } + return to +} + +/** + * Quick object check - this is primarily used to tell + * Objects from primitive values when we know the value + * is a JSON-compliant type. + */ +function isObject (obj) { + return obj !== null && typeof obj === 'object' +} + +/** + * Strict object type check. Only returns true + * for plain JavaScript objects. + */ +var toString = Object.prototype.toString; +var OBJECT_STRING = '[object Object]'; +function isPlainObject (obj) { + return toString.call(obj) === OBJECT_STRING +} + +/** + * Merge an Array of Objects into a single Object. + */ +function toObject (arr) { + var res = {}; + for (var i = 0; i < arr.length; i++) { + if (arr[i]) { + extend(res, arr[i]); + } + } + return res +} + +/** + * Perform no operation. + */ +function noop () {} + +/** + * Always return false. + */ +var no = function () { return false; }; + +/** + * Return same value + */ +var identity = function (_) { return _; }; + +/** + * Generate a static keys string from compiler modules. + */ +function genStaticKeys (modules) { + return modules.reduce(function (keys, m) { + return keys.concat(m.staticKeys || []) + }, []).join(',') +} + +/** + * Check if two values are loosely equal - that is, + * if they are plain objects, do they have the same shape? + */ +function looseEqual (a, b) { + var isObjectA = isObject(a); + var isObjectB = isObject(b); + if (isObjectA && isObjectB) { + return JSON.stringify(a) === JSON.stringify(b) + } else if (!isObjectA && !isObjectB) { + return String(a) === String(b) + } else { + return false + } +} + +function looseIndexOf (arr, val) { + for (var i = 0; i < arr.length; i++) { + if (looseEqual(arr[i], val)) { return i } + } + return -1 +} + +/* */ + +var config = { + /** + * Option merge strategies (used in core/util/options) + */ + optionMergeStrategies: Object.create(null), + + /** + * Whether to suppress warnings. + */ + silent: false, + + /** + * Whether to enable devtools + */ + devtools: "development" !== 'production', + + /** + * Error handler for watcher errors + */ + errorHandler: null, + + /** + * Ignore certain custom elements + */ + ignoredElements: [], + + /** + * Custom user key aliases for v-on + */ + keyCodes: Object.create(null), + + /** + * Check if a tag is reserved so that it cannot be registered as a + * component. This is platform-dependent and may be overwritten. + */ + isReservedTag: no, + + /** + * Check if a tag is an unknown element. + * Platform-dependent. + */ + isUnknownElement: no, + + /** + * Get the namespace of an element + */ + getTagNamespace: noop, + + /** + * Parse the real tag name for the specific platform. + */ + parsePlatformTagName: identity, + + /** + * Check if an attribute must be bound using property, e.g. value + * Platform-dependent. + */ + mustUseProp: no, + + /** + * List of asset types that a component can own. + */ + _assetTypes: [ + 'component', + 'directive', + 'filter' + ], + + /** + * List of lifecycle hooks. + */ + _lifecycleHooks: [ + 'beforeCreate', + 'created', + 'beforeMount', + 'mounted', + 'beforeUpdate', + 'updated', + 'beforeDestroy', + 'destroyed', + 'activated', + 'deactivated' + ], + + /** + * Max circular updates allowed in a scheduler flush cycle. + */ + _maxUpdateCount: 100 +}; + +/* */ + +/** + * Check if a string starts with $ or _ + */ +function isReserved (str) { + var c = (str + '').charCodeAt(0); + return c === 0x24 || c === 0x5F +} + +/** + * Define a property. + */ +function def (obj, key, val, enumerable) { + Object.defineProperty(obj, key, { + value: val, + enumerable: !!enumerable, + writable: true, + configurable: true + }); +} + +/** + * Parse simple path. + */ +var bailRE = /[^\w.$]/; +function parsePath (path) { + if (bailRE.test(path)) { + return + } else { + var segments = path.split('.'); + return function (obj) { + for (var i = 0; i < segments.length; i++) { + if (!obj) { return } + obj = obj[segments[i]]; + } + return obj + } + } +} + +/* */ +/* globals MutationObserver */ + +// can we use __proto__? +var hasProto = '__proto__' in {}; + +// Browser environment sniffing +var inBrowser = typeof window !== 'undefined'; +var UA = inBrowser && window.navigator.userAgent.toLowerCase(); +var isIE = UA && /msie|trident/.test(UA); +var isIE9 = UA && UA.indexOf('msie 9.0') > 0; +var isEdge = UA && UA.indexOf('edge/') > 0; +var isAndroid = UA && UA.indexOf('android') > 0; +var isIOS = UA && /iphone|ipad|ipod|ios/.test(UA); + +// this needs to be lazy-evaled because vue may be required before +// vue-server-renderer can set VUE_ENV +var _isServer; +var isServerRendering = function () { + if (_isServer === undefined) { + /* istanbul ignore if */ + if (!inBrowser && typeof global !== 'undefined') { + // detect presence of vue-server-renderer and avoid + // Webpack shimming the process + _isServer = global['process'].env.VUE_ENV === 'server'; + } else { + _isServer = false; + } + } + return _isServer +}; + +// detect devtools +var devtools = inBrowser && window.__VUE_DEVTOOLS_GLOBAL_HOOK__; + +/* istanbul ignore next */ +function isNative (Ctor) { + return /native code/.test(Ctor.toString()) +} + +/** + * Defer a task to execute it asynchronously. + */ +var nextTick = (function () { + var callbacks = []; + var pending = false; + var timerFunc; + + function nextTickHandler () { + pending = false; + var copies = callbacks.slice(0); + callbacks.length = 0; + for (var i = 0; i < copies.length; i++) { + copies[i](); + } + } + + // the nextTick behavior leverages the microtask queue, which can be accessed + // via either native Promise.then or MutationObserver. + // MutationObserver has wider support, however it is seriously bugged in + // UIWebView in iOS >= 9.3.3 when triggered in touch event handlers. It + // completely stops working after triggering a few times... so, if native + // Promise is available, we will use it: + /* istanbul ignore if */ + if (typeof Promise !== 'undefined' && isNative(Promise)) { + var p = Promise.resolve(); + var logError = function (err) { console.error(err); }; + timerFunc = function () { + p.then(nextTickHandler).catch(logError); + // in problematic UIWebViews, Promise.then doesn't completely break, but + // it can get stuck in a weird state where callbacks are pushed into the + // microtask queue but the queue isn't being flushed, until the browser + // needs to do some other work, e.g. handle a timer. Therefore we can + // "force" the microtask queue to be flushed by adding an empty timer. + if (isIOS) { setTimeout(noop); } + }; + } else if (typeof MutationObserver !== 'undefined' && ( + isNative(MutationObserver) || + // PhantomJS and iOS 7.x + MutationObserver.toString() === '[object MutationObserverConstructor]' + )) { + // use MutationObserver where native Promise is not available, + // e.g. PhantomJS IE11, iOS7, Android 4.4 + var counter = 1; + var observer = new MutationObserver(nextTickHandler); + var textNode = document.createTextNode(String(counter)); + observer.observe(textNode, { + characterData: true + }); + timerFunc = function () { + counter = (counter + 1) % 2; + textNode.data = String(counter); + }; + } else { + // fallback to setTimeout + /* istanbul ignore next */ + timerFunc = function () { + setTimeout(nextTickHandler, 0); + }; + } + + return function queueNextTick (cb, ctx) { + var _resolve; + callbacks.push(function () { + if (cb) { cb.call(ctx); } + if (_resolve) { _resolve(ctx); } + }); + if (!pending) { + pending = true; + timerFunc(); + } + if (!cb && typeof Promise !== 'undefined') { + return new Promise(function (resolve) { + _resolve = resolve; + }) + } + } +})(); + +var _Set; +/* istanbul ignore if */ +if (typeof Set !== 'undefined' && isNative(Set)) { + // use native Set when available. + _Set = Set; +} else { + // a non-standard Set polyfill that only works with primitive keys. + _Set = (function () { + function Set () { + this.set = Object.create(null); + } + Set.prototype.has = function has (key) { + return this.set[key] === true + }; + Set.prototype.add = function add (key) { + this.set[key] = true; + }; + Set.prototype.clear = function clear () { + this.set = Object.create(null); + }; + + return Set; + }()); +} + +var warn = noop; +var formatComponentName; + +{ + var hasConsole = typeof console !== 'undefined'; + + warn = function (msg, vm) { + if (hasConsole && (!config.silent)) { + console.error("[Vue warn]: " + msg + " " + ( + vm ? formatLocation(formatComponentName(vm)) : '' + )); + } + }; + + formatComponentName = function (vm) { + if (vm.$root === vm) { + return 'root instance' + } + var name = vm._isVue + ? vm.$options.name || vm.$options._componentTag + : vm.name; + return ( + (name ? ("component <" + name + ">") : "anonymous component") + + (vm._isVue && vm.$options.__file ? (" at " + (vm.$options.__file)) : '') + ) + }; + + var formatLocation = function (str) { + if (str === 'anonymous component') { + str += " - use the \"name\" option for better debugging messages."; + } + return ("\n(found in " + str + ")") + }; +} + +/* */ + + +var uid$1 = 0; + +/** + * A dep is an observable that can have multiple + * directives subscribing to it. + */ +var Dep = function Dep () { + this.id = uid$1++; + this.subs = []; +}; + +Dep.prototype.addSub = function addSub (sub) { + this.subs.push(sub); +}; + +Dep.prototype.removeSub = function removeSub (sub) { + remove$1(this.subs, sub); +}; + +Dep.prototype.depend = function depend () { + if (Dep.target) { + Dep.target.addDep(this); + } +}; + +Dep.prototype.notify = function notify () { + // stablize the subscriber list first + var subs = this.subs.slice(); + for (var i = 0, l = subs.length; i < l; i++) { + subs[i].update(); + } +}; + +// the current target watcher being evaluated. +// this is globally unique because there could be only one +// watcher being evaluated at any time. +Dep.target = null; +var targetStack = []; + +function pushTarget (_target) { + if (Dep.target) { targetStack.push(Dep.target); } + Dep.target = _target; +} + +function popTarget () { + Dep.target = targetStack.pop(); +} + +/* + * not type checking this file because flow doesn't play well with + * dynamically accessing methods on Array prototype + */ + +var arrayProto = Array.prototype; +var arrayMethods = Object.create(arrayProto);[ + 'push', + 'pop', + 'shift', + 'unshift', + 'splice', + 'sort', + 'reverse' +] +.forEach(function (method) { + // cache original method + var original = arrayProto[method]; + def(arrayMethods, method, function mutator () { + var arguments$1 = arguments; + + // avoid leaking arguments: + // http://jsperf.com/closure-with-arguments + var i = arguments.length; + var args = new Array(i); + while (i--) { + args[i] = arguments$1[i]; + } + var result = original.apply(this, args); + var ob = this.__ob__; + var inserted; + switch (method) { + case 'push': + inserted = args; + break + case 'unshift': + inserted = args; + break + case 'splice': + inserted = args.slice(2); + break + } + if (inserted) { ob.observeArray(inserted); } + // notify change + ob.dep.notify(); + return result + }); +}); + +/* */ + +var arrayKeys = Object.getOwnPropertyNames(arrayMethods); + +/** + * By default, when a reactive property is set, the new value is + * also converted to become reactive. However when passing down props, + * we don't want to force conversion because the value may be a nested value + * under a frozen data structure. Converting it would defeat the optimization. + */ +var observerState = { + shouldConvert: true, + isSettingProps: false +}; + +/** + * Observer class that are attached to each observed + * object. Once attached, the observer converts target + * object's property keys into getter/setters that + * collect dependencies and dispatches updates. + */ +var Observer = function Observer (value) { + this.value = value; + this.dep = new Dep(); + this.vmCount = 0; + def(value, '__ob__', this); + if (Array.isArray(value)) { + var augment = hasProto + ? protoAugment + : copyAugment; + augment(value, arrayMethods, arrayKeys); + this.observeArray(value); + } else { + this.walk(value); + } +}; + +/** + * Walk through each property and convert them into + * getter/setters. This method should only be called when + * value type is Object. + */ +Observer.prototype.walk = function walk (obj) { + var keys = Object.keys(obj); + for (var i = 0; i < keys.length; i++) { + defineReactive$$1(obj, keys[i], obj[keys[i]]); + } +}; + +/** + * Observe a list of Array items. + */ +Observer.prototype.observeArray = function observeArray (items) { + for (var i = 0, l = items.length; i < l; i++) { + observe(items[i]); + } +}; + +// helpers + +/** + * Augment an target Object or Array by intercepting + * the prototype chain using __proto__ + */ +function protoAugment (target, src) { + /* eslint-disable no-proto */ + target.__proto__ = src; + /* eslint-enable no-proto */ +} + +/** + * Augment an target Object or Array by defining + * hidden properties. + */ +/* istanbul ignore next */ +function copyAugment (target, src, keys) { + for (var i = 0, l = keys.length; i < l; i++) { + var key = keys[i]; + def(target, key, src[key]); + } +} + +/** + * Attempt to create an observer instance for a value, + * returns the new observer if successfully observed, + * or the existing observer if the value already has one. + */ +function observe (value, asRootData) { + if (!isObject(value)) { + return + } + var ob; + if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) { + ob = value.__ob__; + } else if ( + observerState.shouldConvert && + !isServerRendering() && + (Array.isArray(value) || isPlainObject(value)) && + Object.isExtensible(value) && + !value._isVue + ) { + ob = new Observer(value); + } + if (asRootData && ob) { + ob.vmCount++; + } + return ob +} + +/** + * Define a reactive property on an Object. + */ +function defineReactive$$1 ( + obj, + key, + val, + customSetter +) { + var dep = new Dep(); + + var property = Object.getOwnPropertyDescriptor(obj, key); + if (property && property.configurable === false) { + return + } + + // cater for pre-defined getter/setters + var getter = property && property.get; + var setter = property && property.set; + + var childOb = observe(val); + Object.defineProperty(obj, key, { + enumerable: true, + configurable: true, + get: function reactiveGetter () { + var value = getter ? getter.call(obj) : val; + if (Dep.target) { + dep.depend(); + if (childOb) { + childOb.dep.depend(); + } + if (Array.isArray(value)) { + dependArray(value); + } + } + return value + }, + set: function reactiveSetter (newVal) { + var value = getter ? getter.call(obj) : val; + /* eslint-disable no-self-compare */ + if (newVal === value || (newVal !== newVal && value !== value)) { + return + } + /* eslint-enable no-self-compare */ + if ("development" !== 'production' && customSetter) { + customSetter(); + } + if (setter) { + setter.call(obj, newVal); + } else { + val = newVal; + } + childOb = observe(newVal); + dep.notify(); + } + }); +} + +/** + * Set a property on an object. Adds the new property and + * triggers change notification if the property doesn't + * already exist. + */ +function set$1 (obj, key, val) { + if (Array.isArray(obj)) { + obj.length = Math.max(obj.length, key); + obj.splice(key, 1, val); + return val + } + if (hasOwn(obj, key)) { + obj[key] = val; + return + } + var ob = obj.__ob__; + if (obj._isVue || (ob && ob.vmCount)) { + "development" !== 'production' && warn( + 'Avoid adding reactive properties to a Vue instance or its root $data ' + + 'at runtime - declare it upfront in the data option.' + ); + return + } + if (!ob) { + obj[key] = val; + return + } + defineReactive$$1(ob.value, key, val); + ob.dep.notify(); + return val +} + +/** + * Delete a property and trigger change if necessary. + */ +function del (obj, key) { + var ob = obj.__ob__; + if (obj._isVue || (ob && ob.vmCount)) { + "development" !== 'production' && warn( + 'Avoid deleting properties on a Vue instance or its root $data ' + + '- just set it to null.' + ); + return + } + if (!hasOwn(obj, key)) { + return + } + delete obj[key]; + if (!ob) { + return + } + ob.dep.notify(); +} + +/** + * Collect dependencies on array elements when the array is touched, since + * we cannot intercept array element access like property getters. + */ +function dependArray (value) { + for (var e = (void 0), i = 0, l = value.length; i < l; i++) { + e = value[i]; + e && e.__ob__ && e.__ob__.dep.depend(); + if (Array.isArray(e)) { + dependArray(e); + } + } +} + +/* */ + +/** + * Option overwriting strategies are functions that handle + * how to merge a parent option value and a child option + * value into the final value. + */ +var strats = config.optionMergeStrategies; + +/** + * Options with restrictions + */ +{ + strats.el = strats.propsData = function (parent, child, vm, key) { + if (!vm) { + warn( + "option \"" + key + "\" can only be used during instance " + + 'creation with the `new` keyword.' + ); + } + return defaultStrat(parent, child) + }; +} + +/** + * Helper that recursively merges two data objects together. + */ +function mergeData (to, from) { + if (!from) { return to } + var key, toVal, fromVal; + var keys = Object.keys(from); + for (var i = 0; i < keys.length; i++) { + key = keys[i]; + toVal = to[key]; + fromVal = from[key]; + if (!hasOwn(to, key)) { + set$1(to, key, fromVal); + } else if (isPlainObject(toVal) && isPlainObject(fromVal)) { + mergeData(toVal, fromVal); + } + } + return to +} + +/** + * Data + */ +strats.data = function ( + parentVal, + childVal, + vm +) { + if (!vm) { + // in a Vue.extend merge, both should be functions + if (!childVal) { + return parentVal + } + if (typeof childVal !== 'function') { + "development" !== 'production' && warn( + 'The "data" option should be a function ' + + 'that returns a per-instance value in component ' + + 'definitions.', + vm + ); + return parentVal + } + if (!parentVal) { + return childVal + } + // when parentVal & childVal are both present, + // we need to return a function that returns the + // merged result of both functions... no need to + // check if parentVal is a function here because + // it has to be a function to pass previous merges. + return function mergedDataFn () { + return mergeData( + childVal.call(this), + parentVal.call(this) + ) + } + } else if (parentVal || childVal) { + return function mergedInstanceDataFn () { + // instance merge + var instanceData = typeof childVal === 'function' + ? childVal.call(vm) + : childVal; + var defaultData = typeof parentVal === 'function' + ? parentVal.call(vm) + : undefined; + if (instanceData) { + return mergeData(instanceData, defaultData) + } else { + return defaultData + } + } + } +}; + +/** + * Hooks and param attributes are merged as arrays. + */ +function mergeHook ( + parentVal, + childVal +) { + return childVal + ? parentVal + ? parentVal.concat(childVal) + : Array.isArray(childVal) + ? childVal + : [childVal] + : parentVal +} + +config._lifecycleHooks.forEach(function (hook) { + strats[hook] = mergeHook; +}); + +/** + * Assets + * + * When a vm is present (instance creation), we need to do + * a three-way merge between constructor options, instance + * options and parent options. + */ +function mergeAssets (parentVal, childVal) { + var res = Object.create(parentVal || null); + return childVal + ? extend(res, childVal) + : res +} + +config._assetTypes.forEach(function (type) { + strats[type + 's'] = mergeAssets; +}); + +/** + * Watchers. + * + * Watchers hashes should not overwrite one + * another, so we merge them as arrays. + */ +strats.watch = function (parentVal, childVal) { + /* istanbul ignore if */ + if (!childVal) { return parentVal } + if (!parentVal) { return childVal } + var ret = {}; + extend(ret, parentVal); + for (var key in childVal) { + var parent = ret[key]; + var child = childVal[key]; + if (parent && !Array.isArray(parent)) { + parent = [parent]; + } + ret[key] = parent + ? parent.concat(child) + : [child]; + } + return ret +}; + +/** + * Other object hashes. + */ +strats.props = +strats.methods = +strats.computed = function (parentVal, childVal) { + if (!childVal) { return parentVal } + if (!parentVal) { return childVal } + var ret = Object.create(null); + extend(ret, parentVal); + extend(ret, childVal); + return ret +}; + +/** + * Default strategy. + */ +var defaultStrat = function (parentVal, childVal) { + return childVal === undefined + ? parentVal + : childVal +}; + +/** + * Validate component names + */ +function checkComponents (options) { + for (var key in options.components) { + var lower = key.toLowerCase(); + if (isBuiltInTag(lower) || config.isReservedTag(lower)) { + warn( + 'Do not use built-in or reserved HTML elements as component ' + + 'id: ' + key + ); + } + } +} + +/** + * Ensure all props option syntax are normalized into the + * Object-based format. + */ +function normalizeProps (options) { + var props = options.props; + if (!props) { return } + var res = {}; + var i, val, name; + if (Array.isArray(props)) { + i = props.length; + while (i--) { + val = props[i]; + if (typeof val === 'string') { + name = camelize(val); + res[name] = { type: null }; + } else { + warn('props must be strings when using array syntax.'); + } + } + } else if (isPlainObject(props)) { + for (var key in props) { + val = props[key]; + name = camelize(key); + res[name] = isPlainObject(val) + ? val + : { type: val }; + } + } + options.props = res; +} + +/** + * Normalize raw function directives into object format. + */ +function normalizeDirectives (options) { + var dirs = options.directives; + if (dirs) { + for (var key in dirs) { + var def = dirs[key]; + if (typeof def === 'function') { + dirs[key] = { bind: def, update: def }; + } + } + } +} + +/** + * Merge two option objects into a new one. + * Core utility used in both instantiation and inheritance. + */ +function mergeOptions ( + parent, + child, + vm +) { + { + checkComponents(child); + } + normalizeProps(child); + normalizeDirectives(child); + var extendsFrom = child.extends; + if (extendsFrom) { + parent = typeof extendsFrom === 'function' + ? mergeOptions(parent, extendsFrom.options, vm) + : mergeOptions(parent, extendsFrom, vm); + } + if (child.mixins) { + for (var i = 0, l = child.mixins.length; i < l; i++) { + var mixin = child.mixins[i]; + if (mixin.prototype instanceof Vue$3) { + mixin = mixin.options; + } + parent = mergeOptions(parent, mixin, vm); + } + } + var options = {}; + var key; + for (key in parent) { + mergeField(key); + } + for (key in child) { + if (!hasOwn(parent, key)) { + mergeField(key); + } + } + function mergeField (key) { + var strat = strats[key] || defaultStrat; + options[key] = strat(parent[key], child[key], vm, key); + } + return options +} + +/** + * Resolve an asset. + * This function is used because child instances need access + * to assets defined in its ancestor chain. + */ +function resolveAsset ( + options, + type, + id, + warnMissing +) { + /* istanbul ignore if */ + if (typeof id !== 'string') { + return + } + var assets = options[type]; + // check local registration variations first + if (hasOwn(assets, id)) { return assets[id] } + var camelizedId = camelize(id); + if (hasOwn(assets, camelizedId)) { return assets[camelizedId] } + var PascalCaseId = capitalize(camelizedId); + if (hasOwn(assets, PascalCaseId)) { return assets[PascalCaseId] } + // fallback to prototype chain + var res = assets[id] || assets[camelizedId] || assets[PascalCaseId]; + if ("development" !== 'production' && warnMissing && !res) { + warn( + 'Failed to resolve ' + type.slice(0, -1) + ': ' + id, + options + ); + } + return res +} + +/* */ + +function validateProp ( + key, + propOptions, + propsData, + vm +) { + var prop = propOptions[key]; + var absent = !hasOwn(propsData, key); + var value = propsData[key]; + // handle boolean props + if (isType(Boolean, prop.type)) { + if (absent && !hasOwn(prop, 'default')) { + value = false; + } else if (!isType(String, prop.type) && (value === '' || value === hyphenate(key))) { + value = true; + } + } + // check default value + if (value === undefined) { + value = getPropDefaultValue(vm, prop, key); + // since the default value is a fresh copy, + // make sure to observe it. + var prevShouldConvert = observerState.shouldConvert; + observerState.shouldConvert = true; + observe(value); + observerState.shouldConvert = prevShouldConvert; + } + { + assertProp(prop, key, value, vm, absent); + } + return value +} + +/** + * Get the default value of a prop. + */ +function getPropDefaultValue (vm, prop, key) { + // no default, return undefined + if (!hasOwn(prop, 'default')) { + return undefined + } + var def = prop.default; + // warn against non-factory defaults for Object & Array + if (isObject(def)) { + "development" !== 'production' && warn( + 'Invalid default value for prop "' + key + '": ' + + 'Props with type Object/Array must use a factory function ' + + 'to return the default value.', + vm + ); + } + // the raw prop value was also undefined from previous render, + // return previous default value to avoid unnecessary watcher trigger + if (vm && vm.$options.propsData && + vm.$options.propsData[key] === undefined && + vm[key] !== undefined) { + return vm[key] + } + // call factory function for non-Function types + return typeof def === 'function' && prop.type !== Function + ? def.call(vm) + : def +} + +/** + * Assert whether a prop is valid. + */ +function assertProp ( + prop, + name, + value, + vm, + absent +) { + if (prop.required && absent) { + warn( + 'Missing required prop: "' + name + '"', + vm + ); + return + } + if (value == null && !prop.required) { + return + } + var type = prop.type; + var valid = !type || type === true; + var expectedTypes = []; + if (type) { + if (!Array.isArray(type)) { + type = [type]; + } + for (var i = 0; i < type.length && !valid; i++) { + var assertedType = assertType(value, type[i]); + expectedTypes.push(assertedType.expectedType || ''); + valid = assertedType.valid; + } + } + if (!valid) { + warn( + 'Invalid prop: type check failed for prop "' + name + '".' + + ' Expected ' + expectedTypes.map(capitalize).join(', ') + + ', got ' + Object.prototype.toString.call(value).slice(8, -1) + '.', + vm + ); + return + } + var validator = prop.validator; + if (validator) { + if (!validator(value)) { + warn( + 'Invalid prop: custom validator check failed for prop "' + name + '".', + vm + ); + } + } +} + +/** + * Assert the type of a value + */ +function assertType (value, type) { + var valid; + var expectedType = getType(type); + if (expectedType === 'String') { + valid = typeof value === (expectedType = 'string'); + } else if (expectedType === 'Number') { + valid = typeof value === (expectedType = 'number'); + } else if (expectedType === 'Boolean') { + valid = typeof value === (expectedType = 'boolean'); + } else if (expectedType === 'Function') { + valid = typeof value === (expectedType = 'function'); + } else if (expectedType === 'Object') { + valid = isPlainObject(value); + } else if (expectedType === 'Array') { + valid = Array.isArray(value); + } else { + valid = value instanceof type; + } + return { + valid: valid, + expectedType: expectedType + } +} + +/** + * Use function string name to check built-in types, + * because a simple equality check will fail when running + * across different vms / iframes. + */ +function getType (fn) { + var match = fn && fn.toString().match(/^\s*function (\w+)/); + return match && match[1] +} + +function isType (type, fn) { + if (!Array.isArray(fn)) { + return getType(fn) === getType(type) + } + for (var i = 0, len = fn.length; i < len; i++) { + if (getType(fn[i]) === getType(type)) { + return true + } + } + /* istanbul ignore next */ + return false +} + + + +var util = Object.freeze({ + defineReactive: defineReactive$$1, + _toString: _toString, + toNumber: toNumber, + makeMap: makeMap, + isBuiltInTag: isBuiltInTag, + remove: remove$1, + hasOwn: hasOwn, + isPrimitive: isPrimitive, + cached: cached, + camelize: camelize, + capitalize: capitalize, + hyphenate: hyphenate, + bind: bind$1, + toArray: toArray, + extend: extend, + isObject: isObject, + isPlainObject: isPlainObject, + toObject: toObject, + noop: noop, + no: no, + identity: identity, + genStaticKeys: genStaticKeys, + looseEqual: looseEqual, + looseIndexOf: looseIndexOf, + isReserved: isReserved, + def: def, + parsePath: parsePath, + hasProto: hasProto, + inBrowser: inBrowser, + UA: UA, + isIE: isIE, + isIE9: isIE9, + isEdge: isEdge, + isAndroid: isAndroid, + isIOS: isIOS, + isServerRendering: isServerRendering, + devtools: devtools, + nextTick: nextTick, + get _Set () { return _Set; }, + mergeOptions: mergeOptions, + resolveAsset: resolveAsset, + get warn () { return warn; }, + get formatComponentName () { return formatComponentName; }, + validateProp: validateProp +}); + +/* not type checking this file because flow doesn't play well with Proxy */ + +var initProxy; + +{ + var allowedGlobals = makeMap( + 'Infinity,undefined,NaN,isFinite,isNaN,' + + 'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,' + + 'Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,' + + 'require' // for Webpack/Browserify + ); + + var warnNonPresent = function (target, key) { + warn( + "Property or method \"" + key + "\" is not defined on the instance but " + + "referenced during render. Make sure to declare reactive data " + + "properties in the data option.", + target + ); + }; + + var hasProxy = + typeof Proxy !== 'undefined' && + Proxy.toString().match(/native code/); + + if (hasProxy) { + var isBuiltInModifier = makeMap('stop,prevent,self,ctrl,shift,alt,meta'); + config.keyCodes = new Proxy(config.keyCodes, { + set: function set (target, key, value) { + if (isBuiltInModifier(key)) { + warn(("Avoid overwriting built-in modifier in config.keyCodes: ." + key)); + return false + } else { + target[key] = value; + return true + } + } + }); + } + + var hasHandler = { + has: function has (target, key) { + var has = key in target; + var isAllowed = allowedGlobals(key) || key.charAt(0) === '_'; + if (!has && !isAllowed) { + warnNonPresent(target, key); + } + return has || !isAllowed + } + }; + + var getHandler = { + get: function get (target, key) { + if (typeof key === 'string' && !(key in target)) { + warnNonPresent(target, key); + } + return target[key] + } + }; + + initProxy = function initProxy (vm) { + if (hasProxy) { + // determine which proxy handler to use + var options = vm.$options; + var handlers = options.render && options.render._withStripped + ? getHandler + : hasHandler; + vm._renderProxy = new Proxy(vm, handlers); + } else { + vm._renderProxy = vm; + } + }; +} + +/* */ + +var VNode = function VNode ( + tag, + data, + children, + text, + elm, + context, + componentOptions +) { + this.tag = tag; + this.data = data; + this.children = children; + this.text = text; + this.elm = elm; + this.ns = undefined; + this.context = context; + this.functionalContext = undefined; + this.key = data && data.key; + this.componentOptions = componentOptions; + this.componentInstance = undefined; + this.parent = undefined; + this.raw = false; + this.isStatic = false; + this.isRootInsert = true; + this.isComment = false; + this.isCloned = false; + this.isOnce = false; +}; + +var prototypeAccessors = { child: {} }; + +// DEPRECATED: alias for componentInstance for backwards compat. +/* istanbul ignore next */ +prototypeAccessors.child.get = function () { + return this.componentInstance +}; + +Object.defineProperties( VNode.prototype, prototypeAccessors ); + +var createEmptyVNode = function () { + var node = new VNode(); + node.text = ''; + node.isComment = true; + return node +}; + +function createTextVNode (val) { + return new VNode(undefined, undefined, undefined, String(val)) +} + +// optimized shallow clone +// used for static nodes and slot nodes because they may be reused across +// multiple renders, cloning them avoids errors when DOM manipulations rely +// on their elm reference. +function cloneVNode (vnode) { + var cloned = new VNode( + vnode.tag, + vnode.data, + vnode.children, + vnode.text, + vnode.elm, + vnode.context, + vnode.componentOptions + ); + cloned.ns = vnode.ns; + cloned.isStatic = vnode.isStatic; + cloned.key = vnode.key; + cloned.isCloned = true; + return cloned +} + +function cloneVNodes (vnodes) { + var res = new Array(vnodes.length); + for (var i = 0; i < vnodes.length; i++) { + res[i] = cloneVNode(vnodes[i]); + } + return res +} + +/* */ + +var hooks = { init: init, prepatch: prepatch, insert: insert, destroy: destroy$1 }; +var hooksToMerge = Object.keys(hooks); + +function createComponent ( + Ctor, + data, + context, + children, + tag +) { + if (!Ctor) { + return + } + + var baseCtor = context.$options._base; + if (isObject(Ctor)) { + Ctor = baseCtor.extend(Ctor); + } + + if (typeof Ctor !== 'function') { + { + warn(("Invalid Component definition: " + (String(Ctor))), context); + } + return + } + + // async component + if (!Ctor.cid) { + if (Ctor.resolved) { + Ctor = Ctor.resolved; + } else { + Ctor = resolveAsyncComponent(Ctor, baseCtor, function () { + // it's ok to queue this on every render because + // $forceUpdate is buffered by the scheduler. + context.$forceUpdate(); + }); + if (!Ctor) { + // return nothing if this is indeed an async component + // wait for the callback to trigger parent update. + return + } + } + } + + // resolve constructor options in case global mixins are applied after + // component constructor creation + resolveConstructorOptions(Ctor); + + data = data || {}; + + // extract props + var propsData = extractProps(data, Ctor); + + // functional component + if (Ctor.options.functional) { + return createFunctionalComponent(Ctor, propsData, data, context, children) + } + + // extract listeners, since these needs to be treated as + // child component listeners instead of DOM listeners + var listeners = data.on; + // replace with listeners with .native modifier + data.on = data.nativeOn; + + if (Ctor.options.abstract) { + // abstract components do not keep anything + // other than props & listeners + data = {}; + } + + // merge component management hooks onto the placeholder node + mergeHooks(data); + + // return a placeholder vnode + var name = Ctor.options.name || tag; + var vnode = new VNode( + ("vue-component-" + (Ctor.cid) + (name ? ("-" + name) : '')), + data, undefined, undefined, undefined, context, + { Ctor: Ctor, propsData: propsData, listeners: listeners, tag: tag, children: children } + ); + return vnode +} + +function createFunctionalComponent ( + Ctor, + propsData, + data, + context, + children +) { + var props = {}; + var propOptions = Ctor.options.props; + if (propOptions) { + for (var key in propOptions) { + props[key] = validateProp(key, propOptions, propsData); + } + } + // ensure the createElement function in functional components + // gets a unique context - this is necessary for correct named slot check + var _context = Object.create(context); + var h = function (a, b, c, d) { return createElement(_context, a, b, c, d, true); }; + var vnode = Ctor.options.render.call(null, h, { + props: props, + data: data, + parent: context, + children: children, + slots: function () { return resolveSlots(children, context); } + }); + if (vnode instanceof VNode) { + vnode.functionalContext = context; + if (data.slot) { + (vnode.data || (vnode.data = {})).slot = data.slot; + } + } + return vnode +} + +function createComponentInstanceForVnode ( + vnode, // we know it's MountedComponentVNode but flow doesn't + parent, // activeInstance in lifecycle state + parentElm, + refElm +) { + var vnodeComponentOptions = vnode.componentOptions; + var options = { + _isComponent: true, + parent: parent, + propsData: vnodeComponentOptions.propsData, + _componentTag: vnodeComponentOptions.tag, + _parentVnode: vnode, + _parentListeners: vnodeComponentOptions.listeners, + _renderChildren: vnodeComponentOptions.children, + _parentElm: parentElm || null, + _refElm: refElm || null + }; + // check inline-template render functions + var inlineTemplate = vnode.data.inlineTemplate; + if (inlineTemplate) { + options.render = inlineTemplate.render; + options.staticRenderFns = inlineTemplate.staticRenderFns; + } + return new vnodeComponentOptions.Ctor(options) +} + +function init ( + vnode, + hydrating, + parentElm, + refElm +) { + if (!vnode.componentInstance || vnode.componentInstance._isDestroyed) { + var child = vnode.componentInstance = createComponentInstanceForVnode( + vnode, + activeInstance, + parentElm, + refElm + ); + child.$mount(hydrating ? vnode.elm : undefined, hydrating); + } else if (vnode.data.keepAlive) { + // kept-alive components, treat as a patch + var mountedNode = vnode; // work around flow + prepatch(mountedNode, mountedNode); + } +} + +function prepatch ( + oldVnode, + vnode +) { + var options = vnode.componentOptions; + var child = vnode.componentInstance = oldVnode.componentInstance; + child._updateFromParent( + options.propsData, // updated props + options.listeners, // updated listeners + vnode, // new parent vnode + options.children // new children + ); +} + +function insert (vnode) { + if (!vnode.componentInstance._isMounted) { + vnode.componentInstance._isMounted = true; + callHook(vnode.componentInstance, 'mounted'); + } + if (vnode.data.keepAlive) { + vnode.componentInstance._inactive = false; + callHook(vnode.componentInstance, 'activated'); + } +} + +function destroy$1 (vnode) { + if (!vnode.componentInstance._isDestroyed) { + if (!vnode.data.keepAlive) { + vnode.componentInstance.$destroy(); + } else { + vnode.componentInstance._inactive = true; + callHook(vnode.componentInstance, 'deactivated'); + } + } +} + +function resolveAsyncComponent ( + factory, + baseCtor, + cb +) { + if (factory.requested) { + // pool callbacks + factory.pendingCallbacks.push(cb); + } else { + factory.requested = true; + var cbs = factory.pendingCallbacks = [cb]; + var sync = true; + + var resolve = function (res) { + if (isObject(res)) { + res = baseCtor.extend(res); + } + // cache resolved + factory.resolved = res; + // invoke callbacks only if this is not a synchronous resolve + // (async resolves are shimmed as synchronous during SSR) + if (!sync) { + for (var i = 0, l = cbs.length; i < l; i++) { + cbs[i](res); + } + } + }; + + var reject = function (reason) { + "development" !== 'production' && warn( + "Failed to resolve async component: " + (String(factory)) + + (reason ? ("\nReason: " + reason) : '') + ); + }; + + var res = factory(resolve, reject); + + // handle promise + if (res && typeof res.then === 'function' && !factory.resolved) { + res.then(resolve, reject); + } + + sync = false; + // return in case resolved synchronously + return factory.resolved + } +} + +function extractProps (data, Ctor) { + // we are only extracting raw values here. + // validation and default values are handled in the child + // component itself. + var propOptions = Ctor.options.props; + if (!propOptions) { + return + } + var res = {}; + var attrs = data.attrs; + var props = data.props; + var domProps = data.domProps; + if (attrs || props || domProps) { + for (var key in propOptions) { + var altKey = hyphenate(key); + checkProp(res, props, key, altKey, true) || + checkProp(res, attrs, key, altKey) || + checkProp(res, domProps, key, altKey); + } + } + return res +} + +function checkProp ( + res, + hash, + key, + altKey, + preserve +) { + if (hash) { + if (hasOwn(hash, key)) { + res[key] = hash[key]; + if (!preserve) { + delete hash[key]; + } + return true + } else if (hasOwn(hash, altKey)) { + res[key] = hash[altKey]; + if (!preserve) { + delete hash[altKey]; + } + return true + } + } + return false +} + +function mergeHooks (data) { + if (!data.hook) { + data.hook = {}; + } + for (var i = 0; i < hooksToMerge.length; i++) { + var key = hooksToMerge[i]; + var fromParent = data.hook[key]; + var ours = hooks[key]; + data.hook[key] = fromParent ? mergeHook$1(ours, fromParent) : ours; + } +} + +function mergeHook$1 (one, two) { + return function (a, b, c, d) { + one(a, b, c, d); + two(a, b, c, d); + } +} + +/* */ + +function mergeVNodeHook (def, hookKey, hook, key) { + key = key + hookKey; + var injectedHash = def.__injected || (def.__injected = {}); + if (!injectedHash[key]) { + injectedHash[key] = true; + var oldHook = def[hookKey]; + if (oldHook) { + def[hookKey] = function () { + oldHook.apply(this, arguments); + hook.apply(this, arguments); + }; + } else { + def[hookKey] = hook; + } + } +} + +/* */ + +var normalizeEvent = cached(function (name) { + var once = name.charAt(0) === '~'; // Prefixed last, checked first + name = once ? name.slice(1) : name; + var capture = name.charAt(0) === '!'; + name = capture ? name.slice(1) : name; + return { + name: name, + once: once, + capture: capture + } +}); + +function createEventHandle (fn) { + var handle = { + fn: fn, + invoker: function () { + var arguments$1 = arguments; + + var fn = handle.fn; + if (Array.isArray(fn)) { + for (var i = 0; i < fn.length; i++) { + fn[i].apply(null, arguments$1); + } + } else { + fn.apply(null, arguments); + } + } + }; + return handle +} + +function updateListeners ( + on, + oldOn, + add, + remove$$1, + vm +) { + var name, cur, old, event; + for (name in on) { + cur = on[name]; + old = oldOn[name]; + event = normalizeEvent(name); + if (!cur) { + "development" !== 'production' && warn( + "Invalid handler for event \"" + (event.name) + "\": got " + String(cur), + vm + ); + } else if (!old) { + if (!cur.invoker) { + cur = on[name] = createEventHandle(cur); + } + add(event.name, cur.invoker, event.once, event.capture); + } else if (cur !== old) { + old.fn = cur; + on[name] = old; + } + } + for (name in oldOn) { + if (!on[name]) { + event = normalizeEvent(name); + remove$$1(event.name, oldOn[name].invoker, event.capture); + } + } +} + +/* */ + +// The template compiler attempts to minimize the need for normalization by +// statically analyzing the template at compile time. +// +// For plain HTML markup, normalization can be completely skipped because the +// generated render function is guaranteed to return Array. There are +// two cases where extra normalization is needed: + +// 1. When the children contains components - because a functional component +// may return an Array instead of a single root. In this case, just a simple +// nomralization is needed - if any child is an Array, we flatten the whole +// thing with Array.prototype.concat. It is guaranteed to be only 1-level deep +// because functional components already normalize their own children. +function simpleNormalizeChildren (children) { + for (var i = 0; i < children.length; i++) { + if (Array.isArray(children[i])) { + return Array.prototype.concat.apply([], children) + } + } + return children +} + +// 2. When the children contains constrcuts that always generated nested Arrays, +// e.g.