diff --git a/models/wiki.go b/models/wiki.go
index 858fe1d6d04a9..50fbe8be600ca 100644
--- a/models/wiki.go
+++ b/models/wiki.go
@@ -9,17 +9,20 @@ import (
 	"net/url"
 	"os"
 	"path/filepath"
+	"reflect"
+	"regexp"
 	"strings"
 
 	"code.gitea.io/gitea/modules/git"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/sync"
+	"code.gitea.io/gitea/modules/util"
 
 	"github.com/unknwon/com"
 )
 
 var (
-	reservedWikiNames = []string{"_pages", "_new", "_edit", "raw"}
+	reservedWikiNames = []string{"_pages", "_new", "_edit", "_delete", "raw"}
 	wikiWorkingPool   = sync.NewExclusivePool()
 )
 
@@ -28,9 +31,17 @@ func NormalizeWikiName(name string) string {
 	return strings.Replace(name, "-", " ", -1)
 }
 
-// WikiNameToSubURL converts a wiki name to its corresponding sub-URL.
+// WikiNameToSubURL converts a wiki name to its corresponding sub-URL. This will escape dangerous letters.
 func WikiNameToSubURL(name string) string {
-	return url.QueryEscape(strings.Replace(name, " ", "-", -1))
+	// remove path up
+	re1 := regexp.MustCompile(`(\.\.\/)`)
+	name = re1.ReplaceAllString(name, "")
+	// trim whitespace and /
+	name = strings.Trim(name, "\n\r\t /")
+	name = url.QueryEscape(name)
+	//restore spaces
+	re3 := regexp.MustCompile(`(?m)(%20|\+)`)
+	return re3.ReplaceAllString(name, "%20")
 }
 
 // WikiNameToFilename converts a wiki name to its corresponding filename.
@@ -39,17 +50,53 @@ func WikiNameToFilename(name string) string {
 	return url.QueryEscape(name) + ".md"
 }
 
+// WikiNameToPathFilename converts a wiki name to its corresponding filename, keep directory paths.
+func WikiNameToPathFilename(name string) string {
+	var restore = [1][2]string{
+		{`(\.\.\/)`, ""}, // remove path up
+	}
+	for _, kv := range restore {
+		loopRe := regexp.MustCompile(kv[0])
+		name = loopRe.ReplaceAllString(name, kv[1])
+	}
+	name = strings.Trim(name, "\n\r\t ./") // trim whitespace and / .
+	return name + ".md"
+}
+
+// FilenameToPathFilename converts a wiki filename to filename with filepath.
+func FilenameToPathFilename(name string) string {
+	// restore spaces and slashes
+	var restore = [4][2]string{
+		{`(?m)%2F`, "/"},      //recover slashes /
+		{`(?m)(%20|\+)`, " "}, //restore spaces
+		{`(?m)(%25)`, "%"},    //restore %
+		{`(?m)(%26)`, "&"},    //restore &
+	}
+	for _, kv := range restore {
+		loopRe := regexp.MustCompile(kv[0])
+		name = loopRe.ReplaceAllString(name, kv[1])
+	}
+	return name
+}
+
+// WikiNameToRawPrefix Get raw file path inside wiki, removes last path element and returns
+func WikiNameToRawPrefix(repositoryName string, wikiPage string) string {
+	a := strings.Split(wikiPage, "/")
+	a = a[:len(a)-1]
+	return util.URLJoin(repositoryName, "wiki", "raw", strings.Join(a, "/"))
+}
+
 // WikiFilenameToName converts a wiki filename to its corresponding page name.
-func WikiFilenameToName(filename string) (string, error) {
+func WikiFilenameToName(filename string) (string, string, error) {
 	if !strings.HasSuffix(filename, ".md") {
-		return "", ErrWikiInvalidFileName{filename}
+		return "", "", ErrWikiInvalidFileName{filename}
 	}
 	basename := filename[:len(filename)-3]
 	unescaped, err := url.QueryUnescape(basename)
 	if err != nil {
-		return "", err
+		return basename, basename, err
 	}
-	return NormalizeWikiName(unescaped), nil
+	return unescaped, basename, nil
 }
 
 // WikiCloneLink returns clone URLs of repository wiki.
@@ -97,6 +144,21 @@ func nameAllowed(name string) error {
 	return nil
 }
 
+// checkNewWikiFilename check filename or file exists inside repository
+func checkNewWikiFilename(repo *git.Repository, name string) (bool, error) {
+	filesInIndex, err := repo.LsFiles(name)
+	if err != nil {
+		log.Error("%v", err)
+		return false, err
+	}
+	for _, file := range filesInIndex {
+		if file == name {
+			return true, ErrWikiAlreadyExist{name}
+		}
+	}
+	return false, nil
+}
+
 // updateWikiPage adds a new page to the repository wiki.
 func (repo *Repository) updateWikiPage(doer *User, oldWikiName, newWikiName, content, message string, isNew bool) (err error) {
 	if err = nameAllowed(newWikiName); err != nil {
@@ -136,6 +198,9 @@ func (repo *Repository) updateWikiPage(doer *User, oldWikiName, newWikiName, con
 	}
 
 	gitRepo, err := git.OpenRepository(basePath)
+
+	fmt.Println(reflect.TypeOf(gitRepo))
+
 	if err != nil {
 		log.Error("Unable to open temporary repository: %s (%v)", basePath, err)
 		return fmt.Errorf("Failed to open new temporary repository in: %s %v", basePath, err)
@@ -149,33 +214,41 @@ func (repo *Repository) updateWikiPage(doer *User, oldWikiName, newWikiName, con
 	}
 
 	newWikiPath := WikiNameToFilename(newWikiName)
+	newWikiDirPath := WikiNameToPathFilename(newWikiName)
+
 	if isNew {
-		filesInIndex, err := gitRepo.LsFiles(newWikiPath)
-		if err != nil {
-			log.Error("%v", err)
+		// check file already exists - plain structure
+		if _, err := checkNewWikiFilename(gitRepo, newWikiPath); err != nil {
 			return err
 		}
-		for _, file := range filesInIndex {
-			if file == newWikiPath {
-				return ErrWikiAlreadyExist{newWikiPath}
-			}
+
+		// check file already exists - directory structure
+		if _, err := checkNewWikiFilename(gitRepo, newWikiDirPath); err != nil {
+			return err
 		}
 	} else {
+		var found bool
+
+		// check file already exists - plain structure
 		oldWikiPath := WikiNameToFilename(oldWikiName)
-		filesInIndex, err := gitRepo.LsFiles(oldWikiPath)
-		if err != nil {
-			log.Error("%v", err)
+		if found, err = checkNewWikiFilename(gitRepo, oldWikiPath); err != nil && !found {
 			return err
 		}
-		found := false
-		for _, file := range filesInIndex {
-			if file == oldWikiPath {
-				found = true
-				break
+		if found {
+			err := gitRepo.RemoveFilesFromIndex(oldWikiPath)
+			if err != nil {
+				log.Error("%v", err)
+				return err
 			}
 		}
+
+		// check file already exists - directory structure
+		oldWikiDirPath := WikiNameToPathFilename(oldWikiName)
+		if found, err = checkNewWikiFilename(gitRepo, oldWikiDirPath); err != nil && !found {
+			return err
+		}
 		if found {
-			err := gitRepo.RemoveFilesFromIndex(oldWikiPath)
+			err := gitRepo.RemoveFilesFromIndex(oldWikiDirPath)
 			if err != nil {
 				log.Error("%v", err)
 				return err
@@ -183,6 +256,8 @@ func (repo *Repository) updateWikiPage(doer *User, oldWikiName, newWikiName, con
 		}
 	}
 
+	newWikiDirPath = FilenameToPathFilename(newWikiDirPath)
+
 	// FIXME: The wiki doesn't have lfs support at present - if this changes need to check attributes here
 
 	objectHash, err := gitRepo.HashObject(strings.NewReader(content))
@@ -191,7 +266,7 @@ func (repo *Repository) updateWikiPage(doer *User, oldWikiName, newWikiName, con
 		return err
 	}
 
-	if err := gitRepo.AddObjectToIndex("100644", objectHash, newWikiPath); err != nil {
+	if err := gitRepo.AddObjectToIndex("100644", objectHash, newWikiDirPath); err != nil {
 		log.Error("%v", err)
 		return err
 	}
@@ -289,14 +364,12 @@ func (repo *Repository) DeleteWikiPage(doer *User, wikiName string) (err error)
 		return fmt.Errorf("Unable to read HEAD tree to index in: %s %v", basePath, err)
 	}
 
+	var found bool
+
+	// check file exists - plain structure
 	wikiPath := WikiNameToFilename(wikiName)
-	filesInIndex, err := gitRepo.LsFiles(wikiPath)
-	found := false
-	for _, file := range filesInIndex {
-		if file == wikiPath {
-			found = true
-			break
-		}
+	if found, err = checkNewWikiFilename(gitRepo, wikiName); err != nil && !found {
+		return err
 	}
 	if found {
 		err := gitRepo.RemoveFilesFromIndex(wikiPath)
@@ -304,7 +377,19 @@ func (repo *Repository) DeleteWikiPage(doer *User, wikiName string) (err error)
 			return err
 		}
 	} else {
-		return os.ErrNotExist
+		// check file exists - plain structure
+		wikiDirPath := WikiNameToPathFilename(wikiName)
+		if found, err = checkNewWikiFilename(gitRepo, wikiDirPath); err != nil && !found {
+			return err
+		}
+		if found {
+			err := gitRepo.RemoveFilesFromIndex(wikiDirPath)
+			if err != nil {
+				return err
+			}
+		} else {
+			return os.ErrNotExist
+		}
 	}
 
 	// FIXME: The wiki doesn't have lfs support at present - if this changes need to check attributes here
diff --git a/models/wiki_test.go b/models/wiki_test.go
index 991a3d95b9036..a9e4610de1548 100644
--- a/models/wiki_test.go
+++ b/models/wiki_test.go
@@ -6,6 +6,7 @@ package models
 
 import (
 	"path/filepath"
+	"regexp"
 	"testing"
 
 	"code.gitea.io/gitea/modules/git"
@@ -30,6 +31,22 @@ func TestNormalizeWikiName(t *testing.T) {
 	}
 }
 
+func TestWikiNameToSubURL(t *testing.T) {
+	type test struct {
+		Expected string
+		WikiName string
+	}
+	for _, test := range []test{
+		{"wiki%2Fpath", "wiki/../path/../../"},
+		{"wiki%2Fpath", " wiki/path ////// "},
+		{"wiki-name", "wiki-name"},
+		{"name%20with%2Fslash", "name with/slash"},
+		{"name%20with%25percent", "name with%percent"},
+	} {
+		assert.Equal(t, test.Expected, WikiNameToSubURL(test.WikiName))
+	}
+}
+
 func TestWikiNameToFilename(t *testing.T) {
 	type test struct {
 		Expected string
@@ -40,48 +57,88 @@ func TestWikiNameToFilename(t *testing.T) {
 		{"wiki-name.md", "wiki-name"},
 		{"name-with%2Fslash.md", "name with/slash"},
 		{"name-with%25percent.md", "name with%percent"},
+		{"wiki-name-with%2Fslash.md", "wiki name with/slash"},
+		{"%24%24%24%25%25%25%5E%5E%26%26%21%40%23%24%28%29%2C.%3C%3E.md", "$$$%%%^^&&!@#$(),.<>"},
 	} {
 		assert.Equal(t, test.Expected, WikiNameToFilename(test.WikiName))
 	}
 }
 
-func TestWikiNameToSubURL(t *testing.T) {
+func TestWikiNameToPathFilename(t *testing.T) {
 	type test struct {
 		Expected string
 		WikiName string
 	}
 	for _, test := range []test{
-		{"wiki-name", "wiki name"},
-		{"wiki-name", "wiki-name"},
-		{"name-with%2Fslash", "name with/slash"},
-		{"name-with%25percent", "name with%percent"},
+		{"wiki name.md", "wiki name"},
+		{"wiki-name.md", "wiki-name"},
+		{"name with/slash.md", "name with/slash"},
+		{"name with/slash.md", "name with/../slash"},
+		{"name with%percent.md", "name with%percent"},
+		{"git/config.md", ".git/config   "},
 	} {
-		assert.Equal(t, test.Expected, WikiNameToSubURL(test.WikiName))
+		assert.Equal(t, test.Expected, WikiNameToPathFilename(test.WikiName))
 	}
 }
 
-func TestWikiFilenameToName(t *testing.T) {
+func TestFilenameToPathFilename(t *testing.T) {
 	type test struct {
 		Expected string
 		Filename string
 	}
 	for _, test := range []test{
-		{"hello world", "hello-world.md"},
-		{"symbols/?*", "symbols%2F%3F%2A.md"},
+		{"wiki/name.md", "wiki%2Fname.md"},
+		{"wiki name path", "wiki%20name+path"},
+		{"name with/slash", "name with/slash"},
+		{"name with&and", "name with%2526and"},
+		{"name with%percent", "name with%percent"},
+		{"&&&&", "%26%26%26%26"},
 	} {
-		name, err := WikiFilenameToName(test.Filename)
+		assert.Equal(t, test.Expected, FilenameToPathFilename(test.Filename))
+	}
+}
+
+func TestWikiNameToRawPrefix(t *testing.T) {
+	type test struct {
+		RepoName string
+		WikiPage string
+		Expected string
+	}
+	for _, test := range []test{
+		{"/repo1/name", "wiki/path", "/repo1/name/wiki/raw/wiki"},
+		{"/repo2/name", "wiki/path/subdir", "/repo2/name/wiki/raw/wiki/path"},
+	} {
+		assert.Equal(t, test.Expected, WikiNameToRawPrefix(test.RepoName, test.WikiPage))
+	}
+}
+
+func TestWikiFilenameToName(t *testing.T) {
+	type test struct {
+		Expected1 string
+		Expected2 string
+		Filename  string
+	}
+	for _, test := range []test{
+		{"hello world", "hello world", "hello world.md"},
+		{"hello-world", "hello-world", "hello-world.md"},
+		{"symbols/?*", "symbols%2F%3F%2A", "symbols%2F%3F%2A.md"},
+		{"wiki-name-with/slash", "wiki-name-with%2Fslash", "wiki-name-with%2Fslash.md"},
+		{"$$$%%%^^&&!@#$(),.<>", "%24%24%24%25%25%25%5E%5E%26%26%21%40%23%24%28%29%2C.%3C%3E", "%24%24%24%25%25%25%5E%5E%26%26%21%40%23%24%28%29%2C.%3C%3E.md"},
+	} {
+		unescaped, basename, err := WikiFilenameToName(test.Filename)
 		assert.NoError(t, err)
-		assert.Equal(t, test.Expected, name)
+		assert.Equal(t, test.Expected1, unescaped)
+		assert.Equal(t, test.Expected2, basename)
 	}
 	for _, badFilename := range []string{
 		"nofileextension",
 		"wrongfileextension.txt",
 	} {
-		_, err := WikiFilenameToName(badFilename)
+		_, _, err := WikiFilenameToName(badFilename)
 		assert.Error(t, err)
 		assert.True(t, IsErrWikiInvalidFileName(err))
 	}
-	_, err := WikiFilenameToName("badescaping%%.md")
+	_, _, err := WikiFilenameToName("badescaping%%.md")
 	assert.Error(t, err)
 	assert.False(t, IsErrWikiInvalidFileName(err))
 }
@@ -96,9 +153,9 @@ func TestWikiNameToFilenameToName(t *testing.T) {
 		"$$$%%%^^&&!@#$(),.<>",
 	} {
 		filename := WikiNameToFilename(name)
-		resultName, err := WikiFilenameToName(filename)
+		resultName, _, err := WikiFilenameToName(filename)
 		assert.NoError(t, err)
-		assert.Equal(t, NormalizeWikiName(name), resultName)
+		assert.Equal(t, NormalizeWikiName(name), NormalizeWikiName(resultName))
 	}
 }
 
@@ -163,10 +220,12 @@ func TestRepository_AddWikiPage(t *testing.T) {
 			assert.NoError(t, err)
 			masterTree, err := gitRepo.GetTree("master")
 			assert.NoError(t, err)
-			wikiPath := WikiNameToFilename(wikiName)
+			wikiPath := WikiNameToPathFilename(wikiName)
 			entry, err := masterTree.GetTreeEntryByPath(wikiPath)
+			re := regexp.MustCompile(`(?m)(.*)(\/)([^\/]*)$`)
+
 			assert.NoError(t, err)
-			assert.Equal(t, wikiPath, entry.Name(), "%s not addded correctly", wikiName)
+			assert.Equal(t, re.ReplaceAllString(wikiPath, "$3"), entry.Name(), "%s not addded correctly", wikiName)
 		})
 	}
 
@@ -205,10 +264,13 @@ func TestRepository_EditWikiPage(t *testing.T) {
 		assert.NoError(t, err)
 		masterTree, err := gitRepo.GetTree("master")
 		assert.NoError(t, err)
-		wikiPath := WikiNameToFilename(newWikiName)
+		re := regexp.MustCompile(`(?m)(.*)(\/)([^\/]*)$`)
+
+		wikiPath := WikiNameToPathFilename(newWikiName)
+
 		entry, err := masterTree.GetTreeEntryByPath(wikiPath)
 		assert.NoError(t, err)
-		assert.Equal(t, wikiPath, entry.Name(), "%s not editted correctly", newWikiName)
+		assert.Equal(t, re.ReplaceAllString(wikiPath, "$3"), entry.Name(), "%s not editted correctly", newWikiName)
 
 		if newWikiName != "Home" {
 			_, err := masterTree.GetTreeEntryByPath("Home.md")
diff --git a/modules/markup/markdown/markdown.go b/modules/markup/markdown/markdown.go
index ff78d7ea3a8e4..0946f72b6cbac 100644
--- a/modules/markup/markdown/markdown.go
+++ b/modules/markup/markdown/markdown.go
@@ -127,6 +127,28 @@ func (r *Renderer) RenderNode(w io.Writer, node *blackfriday.Node, entering bool
 	return r.Renderer.RenderNode(w, node, entering)
 }
 
+// Image defines how images should be processed to produce corresponding HTML elements.
+func (r *Renderer) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) {
+	prefix := r.URLPrefix
+	if r.IsWiki {
+		prefix = util.URLJoin(prefix, "wiki", "raw")
+	}
+	prefix = strings.Replace(prefix, "/src/", "/media/", 1)
+	if len(link) > 0 && !markup.IsLink(link) {
+		lnk := string(link)
+		lnk = util.URLJoin(prefix, lnk)
+		lnk = strings.Replace(lnk, " ", "+", -1)
+		link = []byte(lnk)
+	}
+
+	// Put a link around it pointing to itself by default
+	out.WriteString(`<a href="`)
+	out.Write(link)
+	out.WriteString(`">`)
+	r.Renderer.Image(out, link, title, alt)
+	out.WriteString("</a>")
+}
+
 const (
 	blackfridayExtensions = 0 |
 		blackfriday.NoIntraEmphasis |
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index 4433c5bb2abc4..54e9843557f97 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -1077,6 +1077,7 @@ wiki.default_commit_message = Write a note about this page update (optional).
 wiki.save_page = Save Page
 wiki.last_commit_info = %s edited this page %s
 wiki.edit_page_button = Edit
+wiki.abort_edit_page_button = Abort
 wiki.new_page_button = New Page
 wiki.file_revision = Page Revision
 wiki.wiki_page_revisions = Wiki Page Revisions
diff --git a/public/js/index.js b/public/js/index.js
index 93ac6a217810e..7ae561bb1404a 100644
--- a/public/js/index.js
+++ b/public/js/index.js
@@ -1264,20 +1264,29 @@ function initWikiForm() {
             forceSync: true,
             previewRender: function (plainText, preview) { // Async method
                 setTimeout(function () {
-                    // FIXME: still send render request when return back to edit mode
-                    $.post($editArea.data('url'), {
-                            "_csrf": csrf,
-                            "mode": "gfm",
-                            "context": $editArea.data('context'),
-                            "text": plainText
-                        },
-                        function (data) {
-                            preview.innerHTML = '<div class="markdown ui segment">' + data + '</div>';
-                            emojify.run($('.editor-preview')[0]);
-                        }
-                    );
-                }, 0);
-
+                    let $toolbar = $(preview).closest('.CodeMirror-wrap').prev();
+                    if (/(editor-preview-active-side)/.test(preview.className) || $toolbar.length > 0 && $toolbar.hasClass('disabled-for-preview') ) {
+                        const render = function () {
+                            $.post($editArea.data('url'), {
+                                    "_csrf": csrf,
+                                    "mode": "gfm",
+                                    "wiki": true,
+                                    "context": decodeURIComponent($editArea.data('context')),
+                                    "text": plainText
+                                },
+                                function (data) {
+                                    preview.innerHTML = '<div class="markdown ui segment">' + data + '</div>';
+                                    emojify.run($('.editor-preview')[0]);
+                                    // run highlighting on preview
+                                    $(preview).find('pre code').each(function (_, e) {
+                                        hljs.highlightBlock(e);
+                                    });
+                                }
+                            );
+                        };
+                        render();
+                    }
+                }, 3); // in some cases the ui need to be updated before this
                 return "Loading...";
             },
             renderingConfig: {
diff --git a/routers/repo/wiki.go b/routers/repo/wiki.go
index 02fbe4a1ddad6..507ea468642b7 100644
--- a/routers/repo/wiki.go
+++ b/routers/repo/wiki.go
@@ -65,7 +65,7 @@ type PageMeta struct {
 
 // findEntryForFile finds the tree entry for a target filepath.
 func findEntryForFile(commit *git.Commit, target string) (*git.TreeEntry, error) {
-	entries, err := commit.ListEntries()
+	entries, err := commit.ListEntriesRecursive()
 	if err != nil {
 		return nil, err
 	}
@@ -124,12 +124,20 @@ func wikiContentsByEntry(ctx *context.Context, entry *git.TreeEntry) []byte {
 func wikiContentsByName(ctx *context.Context, commit *git.Commit, wikiName string) ([]byte, *git.TreeEntry, string, bool) {
 	var entry *git.TreeEntry
 	var err error
-	pageFilename := models.WikiNameToFilename(wikiName)
+	// check new file structure with directories
+	pageFilename := models.WikiNameToPathFilename(wikiName)
 	if entry, err = findEntryForFile(commit, pageFilename); err != nil {
 		ctx.ServerError("findEntryForFile", err)
 		return nil, nil, "", false
 	} else if entry == nil {
-		return nil, nil, "", true
+		// check old file structure without directories
+		pageFilename = models.WikiNameToFilename(wikiName)
+		if entry, err = findEntryForFile(commit, pageFilename); err != nil {
+			ctx.ServerError("findEntryForFile", err)
+			return nil, nil, "", false
+		} else if entry == nil {
+			return nil, nil, "", true
+		}
 	}
 	return wikiContentsByEntry(ctx, entry), entry, pageFilename, false
 }
@@ -144,9 +152,9 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
 	}
 
 	// Get page list.
-	entries, err := commit.ListEntries()
+	entries, err := commit.Tree.ListEntriesRecursive()
 	if err != nil {
-		ctx.ServerError("ListEntries", err)
+		ctx.ServerError("ListEntriesRecursive", err)
 		return nil, nil
 	}
 	pages := make([]PageMeta, 0, len(entries))
@@ -154,25 +162,27 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
 		if !entry.IsRegular() {
 			continue
 		}
-		wikiName, err := models.WikiFilenameToName(entry.Name())
+		wikiUnescapedName, wikiName, err := models.WikiFilenameToName(entry.Name())
 		if err != nil {
 			if models.IsErrWikiInvalidFileName(err) {
 				continue
 			}
-			ctx.ServerError("WikiFilenameToName", err)
-			return nil, nil
-		} else if wikiName == "_Sidebar" || wikiName == "_Footer" {
+			if _, ok := err.(url.EscapeError); !ok {
+				ctx.ServerError("WikiFilenameToName", err)
+				return nil, nil
+			}
+		} else if wikiUnescapedName == "_Sidebar" || wikiUnescapedName == "_Footer" {
 			continue
 		}
 		pages = append(pages, PageMeta{
-			Name:   wikiName,
+			Name:   wikiUnescapedName,
 			SubURL: models.WikiNameToSubURL(wikiName),
 		})
 	}
 	ctx.Data["Pages"] = pages
 
 	// get requested pagename
-	pageName := models.NormalizeWikiName(ctx.Params(":page"))
+	pageName := ctx.Params(":page")
 	if len(pageName) == 0 {
 		pageName = "Home"
 	}
@@ -202,7 +212,7 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
 	}
 
 	metas := ctx.Repo.Repository.ComposeMetas()
-	ctx.Data["content"] = markdown.RenderWiki(data, ctx.Repo.RepoLink, metas)
+	ctx.Data["content"] = markdown.RenderWiki(data, models.WikiNameToRawPrefix(ctx.Repo.RepoLink, pageFilename), metas)
 	ctx.Data["sidebarPresent"] = sidebarContent != nil
 	ctx.Data["sidebarContent"] = markdown.RenderWiki(sidebarContent, ctx.Repo.RepoLink, metas)
 	ctx.Data["footerPresent"] = footerContent != nil
@@ -225,7 +235,7 @@ func renderRevisionPage(ctx *context.Context) (*git.Repository, *git.TreeEntry)
 	}
 
 	// get requested pagename
-	pageName := models.NormalizeWikiName(ctx.Params(":page"))
+	pageName := ctx.Params(":page")
 	if len(pageName) == 0 {
 		pageName = "Home"
 	}
@@ -288,7 +298,7 @@ func renderEditPage(ctx *context.Context) {
 	}
 
 	// get requested pagename
-	pageName := models.NormalizeWikiName(ctx.Params(":page"))
+	pageName := ctx.Params(":page")
 	if len(pageName) == 0 {
 		pageName = "Home"
 	}
@@ -400,31 +410,42 @@ func WikiPages(ctx *context.Context) {
 		return
 	}
 
-	entries, err := commit.ListEntries()
+	entries, err := commit.Tree.ListEntriesRecursive()
 	if err != nil {
-		ctx.ServerError("ListEntries", err)
+		ctx.ServerError("ListEntriesRecursive", err)
 		return
 	}
 	pages := make([]PageMeta, 0, len(entries))
+LoopPages:
 	for _, entry := range entries {
+		blacklistWikifiles := strings.Split(".gitignore,.git", ",")
+		for _, b := range blacklistWikifiles {
+			if entry.Name() == b || strings.HasSuffix(entry.Name(), b) {
+				continue LoopPages
+			}
+		}
+
 		if !entry.IsRegular() {
 			continue
 		}
+
 		c, err := wikiRepo.GetCommitByPath(entry.Name())
 		if err != nil {
 			ctx.ServerError("GetCommit", err)
 			return
 		}
-		wikiName, err := models.WikiFilenameToName(entry.Name())
+		wikiUnescapedName, wikiName, err := models.WikiFilenameToName(entry.Name())
 		if err != nil {
 			if models.IsErrWikiInvalidFileName(err) {
 				continue
 			}
-			ctx.ServerError("WikiFilenameToName", err)
-			return
+			if _, ok := err.(url.EscapeError); !ok {
+				ctx.ServerError("WikiFilenameToName", err)
+				return
+			}
 		}
 		pages = append(pages, PageMeta{
-			Name:        wikiName,
+			Name:        wikiUnescapedName,
 			SubURL:      models.WikiNameToSubURL(wikiName),
 			UpdatedUnix: timeutil.TimeStamp(c.Author.When.Unix()),
 		})
@@ -487,6 +508,13 @@ func NewWiki(ctx *context.Context) {
 
 	if !ctx.Repo.Repository.HasWiki() {
 		ctx.Data["title"] = "Home"
+	} else if len(ctx.Params(":page")) != 0 {
+		// create files on same subdiretory like current file
+		wikiName := ctx.Params(":page")
+		// remove current filename
+		a := strings.Split(wikiName, "/")
+		a[len(a)-1] = "New Page"
+		ctx.Data["title"] = strings.Join(a, "/")
 	}
 
 	ctx.HTML(200, tplWikiNew)
@@ -508,7 +536,7 @@ func NewWikiPost(ctx *context.Context, form auth.NewWikiForm) {
 		return
 	}
 
-	wikiName := models.NormalizeWikiName(form.Title)
+	wikiName := form.Title
 	if err := ctx.Repo.Repository.AddWikiPage(ctx.User, wikiName, form.Content, form.Message); err != nil {
 		if models.IsErrWikiReservedName(err) {
 			ctx.Data["Err_Title"] = true
@@ -522,6 +550,12 @@ func NewWikiPost(ctx *context.Context, form auth.NewWikiForm) {
 		return
 	}
 
+	// redirect to may changed filename
+	wikiName = models.FilenameToPathFilename(models.WikiNameToPathFilename(wikiName))
+	if strings.HasSuffix(wikiName, ".md") {
+		wikiName = wikiName[:len(wikiName)-3]
+	}
+
 	ctx.Redirect(ctx.Repo.RepoLink + "/wiki/" + models.WikiNameToSubURL(wikiName))
 }
 
@@ -555,20 +589,26 @@ func EditWikiPost(ctx *context.Context, form auth.NewWikiForm) {
 		return
 	}
 
-	oldWikiName := models.NormalizeWikiName(ctx.Params(":page"))
-	newWikiName := models.NormalizeWikiName(form.Title)
+	oldWikiName := ctx.Params(":page")
+	newWikiName := form.Title
 
 	if err := ctx.Repo.Repository.EditWikiPage(ctx.User, oldWikiName, newWikiName, form.Content, form.Message); err != nil {
 		ctx.ServerError("EditWikiPage", err)
 		return
 	}
 
+	// redirect to may changed filename
+	newWikiName = models.FilenameToPathFilename(models.WikiNameToPathFilename(newWikiName))
+	if strings.HasSuffix(newWikiName, ".md") {
+		newWikiName = newWikiName[:len(newWikiName)-3]
+	}
+
 	ctx.Redirect(ctx.Repo.RepoLink + "/wiki/" + models.WikiNameToSubURL(newWikiName))
 }
 
 // DeleteWikiPagePost delete wiki page
 func DeleteWikiPagePost(ctx *context.Context) {
-	wikiName := models.NormalizeWikiName(ctx.Params(":page"))
+	wikiName := ctx.Params(":page")
 	if len(wikiName) == 0 {
 		wikiName = "Home"
 	}
diff --git a/routers/repo/wiki_test.go b/routers/repo/wiki_test.go
index 4687d24f6b28d..ecda2c9fc8b5d 100644
--- a/routers/repo/wiki_test.go
+++ b/routers/repo/wiki_test.go
@@ -25,12 +25,15 @@ func wikiEntry(t *testing.T, repo *models.Repository, wikiName string) *git.Tree
 	assert.NoError(t, err)
 	commit, err := wikiRepo.GetBranchCommit("master")
 	assert.NoError(t, err)
-	entries, err := commit.ListEntries()
+	entries, err := commit.ListEntriesRecursive()
 	assert.NoError(t, err)
 	for _, entry := range entries {
 		if entry.Name() == models.WikiNameToFilename(wikiName) {
 			return entry
 		}
+		if entry.Name() == models.WikiNameToPathFilename(wikiName) {
+			return entry
+		}
 	}
 	return nil
 }
@@ -78,7 +81,7 @@ func TestWiki(t *testing.T) {
 	Wiki(ctx)
 	assert.EqualValues(t, http.StatusOK, ctx.Resp.Status())
 	assert.EqualValues(t, "Home", ctx.Data["Title"])
-	assertPagesMetas(t, []string{"Home", "Page With Image", "Page With Spaced Name"}, ctx.Data["Pages"])
+	assertPagesMetas(t, []string{"Home", "Page-With-Image", "Page-With-Spaced-Name"}, ctx.Data["Pages"])
 }
 
 func TestWikiPages(t *testing.T) {
@@ -88,7 +91,7 @@ func TestWikiPages(t *testing.T) {
 	test.LoadRepo(t, ctx, 1)
 	WikiPages(ctx)
 	assert.EqualValues(t, http.StatusOK, ctx.Resp.Status())
-	assertPagesMetas(t, []string{"Home", "Page With Image", "Page With Spaced Name"}, ctx.Data["Pages"])
+	assertPagesMetas(t, []string{"Home", "Page-With-Image", "Page-With-Spaced-Name"}, ctx.Data["Pages"])
 }
 
 func TestNewWiki(t *testing.T) {
@@ -179,7 +182,7 @@ func TestEditWikiPost(t *testing.T) {
 func TestDeleteWikiPagePost(t *testing.T) {
 	models.PrepareTestEnv(t)
 
-	ctx := test.MockContext(t, "user2/repo1/wiki/Home/delete")
+	ctx := test.MockContext(t, "user2/repo1/wiki/Home/_delete")
 	test.LoadUser(t, ctx, 2)
 	test.LoadRepo(t, ctx, 1)
 	DeleteWikiPagePost(ctx)
diff --git a/routers/routes/routes.go b/routers/routes/routes.go
index 13a5bb27084d0..baff8d7720d5f 100644
--- a/routers/routes/routes.go
+++ b/routers/routes/routes.go
@@ -836,9 +836,10 @@ func RegisterRoutes(m *macaron.Macaron) {
 			m.Group("", func() {
 				m.Combo("/_new").Get(repo.NewWiki).
 					Post(bindIgnErr(auth.NewWikiForm{}), repo.NewWikiPost)
+				m.Get("/:page/_new/", repo.NewWiki)
 				m.Combo("/:page/_edit").Get(repo.EditWiki).
 					Post(bindIgnErr(auth.NewWikiForm{}), repo.EditWikiPost)
-				m.Post("/:page/delete", repo.DeleteWikiPagePost)
+				m.Post("/:page/_delete", repo.DeleteWikiPagePost)
 			}, context.RepoMustNotBeArchived(), reqSignIn, reqRepoWikiWriter)
 		}, repo.MustEnableWiki, context.RepoRef())
 
diff --git a/templates/repo/wiki/new.tmpl b/templates/repo/wiki/new.tmpl
index bf6c24220bdde..2b8aa477208e7 100644
--- a/templates/repo/wiki/new.tmpl
+++ b/templates/repo/wiki/new.tmpl
@@ -7,22 +7,27 @@
 			{{.i18n.Tr "repo.wiki.new_page"}}
 			{{if .PageIsWikiEdit}}
 				<div class="ui right">
-					<a class="ui green small button" href="{{.RepoLink}}/wiki/_new">{{.i18n.Tr "repo.wiki.new_page_button"}}</a>
+					<a class="ui green small button" href="{{.RepoLink}}/wiki/{{.PageURL}}/_new">{{.i18n.Tr "repo.wiki.new_page_button"}}</a>
 				</div>
 			{{end}}
 		</div>
+		{{if .PageIsWikiEdit}}
 		<form class="ui form" action="{{.Link}}" method="post">
+		{{else}}
+		<form class="ui form" action="{{.RepoLink}}/wiki/_new" method="post">
+		{{end}}
 			{{.CsrfTokenHtml}}
 			<div class="field {{if .Err_Title}}error{{end}}">
 				<input name="title" value="{{.title}}" autofocus required>
 			</div>
 			<div class="field">
-				<textarea class="js-quick-submit" id="edit_area" name="content" data-id="wiki-{{.title}}" data-url="{{.Repository.APIURL}}/markdown" data-context="{{.RepoLink}}/wiki" required>{{if .PageIsWikiEdit}}{{.content}}{{else}}{{.i18n.Tr "repo.wiki.welcome"}}{{end}}</textarea>
+				<textarea class="js-quick-submit" id="edit_area" name="content" data-id="wiki-{{.title}}" data-url="{{.Repository.APIURL}}/markdown" data-context="{{.RepoLink}}/wiki/raw/{{.PageURL}}/../" required>{{if .PageIsWikiEdit}}{{.content}}{{else}}{{.i18n.Tr "repo.wiki.welcome"}}{{end}}</textarea>
 			</div>
 			<div class="field">
 				<input name="message" placeholder="{{.i18n.Tr "repo.wiki.default_commit_message"}}">
 			</div>
 			<div class="text right">
+				<a class="ui small red button" href="{{.RepoLink}}/wiki/{{.PageURL}}">{{.i18n.Tr "repo.wiki.abort_edit_page_button"}}</a>
 				<button class="ui green button">
 					{{.i18n.Tr "repo.wiki.save_page"}}
 				</button>
diff --git a/templates/repo/wiki/view.tmpl b/templates/repo/wiki/view.tmpl
index f775ac9429200..9e09a85aa9c7d 100644
--- a/templates/repo/wiki/view.tmpl
+++ b/templates/repo/wiki/view.tmpl
@@ -67,8 +67,8 @@
 					{{if and .CanWriteWiki (not .Repository.IsMirror)}}
 						<div class="ui right">
 							<a class="ui small button" href="{{.RepoLink}}/wiki/{{.PageURL}}/_edit">{{.i18n.Tr "repo.wiki.edit_page_button"}}</a>
-							<a class="ui green small button" href="{{.RepoLink}}/wiki/_new">{{.i18n.Tr "repo.wiki.new_page_button"}}</a>
-							<a class="ui red small button delete-button" href="" data-url="{{.RepoLink}}/wiki/{{.PageURL}}/delete" data-id="{{.PageURL}}">{{.i18n.Tr "repo.wiki.delete_page_button"}}</a>
+							<a class="ui green small button" href="{{.RepoLink}}/wiki/{{.PageURL}}/_new">{{.i18n.Tr "repo.wiki.new_page_button"}}</a>
+							<a class="ui red small button delete-button" href="" data-url="{{.RepoLink}}/wiki/{{.PageURL}}/_delete" data-id="{{.PageURL}}">{{.i18n.Tr "repo.wiki.delete_page_button"}}</a>
 						</div>
 					{{end}}
 				</div>