Dan Brown

Extracted page form js and added better page content linking

...@@ -63,22 +63,14 @@ class PageController extends Controller ...@@ -63,22 +63,14 @@ class PageController extends Controller
63 'html' => 'required|string', 63 'html' => 'required|string',
64 'parent' => 'integer|exists:pages,id' 64 'parent' => 'integer|exists:pages,id'
65 ]); 65 ]);
66 - $book = $this->bookRepo->getBySlug($bookSlug);
67 - $page = $this->pageRepo->newFromInput($request->all());
68 66
69 - $page->slug = $this->pageRepo->findSuitableSlug($page->name, $book->id); 67 + $input = $request->all();
70 - $page->priority = $this->bookRepo->getNewPriority($book); 68 + $book = $this->bookRepo->getBySlug($bookSlug);
69 + $chapterId = ($request->has('chapter') && $this->chapterRepo->idExists($request->get('chapter'))) ? $request->get('chapter') : null;
70 + $input['priority'] = $this->bookRepo->getNewPriority($book);
71 71
72 - if ($request->has('chapter') && $this->chapterRepo->idExists($request->get('chapter'))) { 72 + $page = $this->pageRepo->saveNew($input, $book, $chapterId);
73 - $page->chapter_id = $request->get('chapter');
74 - }
75 73
76 - $page->book_id = $book->id;
77 - $page->text = strip_tags($page->html);
78 - $page->created_by = Auth::user()->id;
79 - $page->updated_by = Auth::user()->id;
80 - $page->save();
81 - $this->pageRepo->saveRevision($page);
82 Activity::add($page, 'page_create', $book->id); 74 Activity::add($page, 'page_create', $book->id);
83 return redirect($page->getUrl()); 75 return redirect($page->getUrl());
84 } 76 }
......
1 <?php namespace BookStack\Repos; 1 <?php namespace BookStack\Repos;
2 2
3 3
4 +use BookStack\Book;
5 +use BookStack\Chapter;
6 +use Illuminate\Http\Request;
4 use Illuminate\Support\Facades\Auth; 7 use Illuminate\Support\Facades\Auth;
8 +use Illuminate\Support\Facades\Log;
5 use Illuminate\Support\Str; 9 use Illuminate\Support\Str;
6 use BookStack\Page; 10 use BookStack\Page;
7 use BookStack\PageRevision; 11 use BookStack\PageRevision;
...@@ -42,6 +46,10 @@ class PageRepo ...@@ -42,6 +46,10 @@ class PageRepo
42 return $this->page->where('slug', '=', $slug)->where('book_id', '=', $bookId)->first(); 46 return $this->page->where('slug', '=', $slug)->where('book_id', '=', $bookId)->first();
43 } 47 }
44 48
49 + /**
50 + * @param $input
51 + * @return Page
52 + */
45 public function newFromInput($input) 53 public function newFromInput($input)
46 { 54 {
47 $page = $this->page->fill($input); 55 $page = $this->page->fill($input);
...@@ -53,6 +61,83 @@ class PageRepo ...@@ -53,6 +61,83 @@ class PageRepo
53 return $this->page->where('slug', '=', $slug)->where('book_id', '=', $bookId)->count(); 61 return $this->page->where('slug', '=', $slug)->where('book_id', '=', $bookId)->count();
54 } 62 }
55 63
64 + /**
65 + * Save a new page into the system.
66 + * Input validation must be done beforehand.
67 + * @param array $input
68 + * @param Book $book
69 + * @param int $chapterId
70 + * @return Page
71 + */
72 + public function saveNew(array $input, Book $book, $chapterId = null)
73 + {
74 + $page = $this->newFromInput($input);
75 + $page->slug = $this->findSuitableSlug($page->name, $book->id);
76 +
77 + if ($chapterId) $page->chapter_id = $chapterId;
78 +
79 + $page->html = $this->formatHtml($input['html']);
80 + $page->text = strip_tags($page->html);
81 + $page->created_by = auth()->user()->id;
82 + $page->updated_by = auth()->user()->id;
83 +
84 + $book->pages()->save($page);
85 + $this->saveRevision($page);
86 + return $page;
87 + }
88 +
89 + /**
90 + * Formats a page's html to be tagged correctly
91 + * within the system.
92 + * @param string $htmlText
93 + * @return string
94 + */
95 + protected function formatHtml($htmlText)
96 + {
97 + libxml_use_internal_errors(true);
98 + $doc = new \DOMDocument();
99 + $doc->loadHTML($htmlText);
100 +
101 + $container = $doc->documentElement;
102 + $body = $container->childNodes[0];
103 + $childNodes = $body->childNodes;
104 +
105 + // Ensure no duplicate ids are used
106 + $lastId = false;
107 + $idArray = [];
108 +
109 + foreach ($childNodes as $index => $childNode) {
110 + /** @var \DOMElement $childNode */
111 + if (get_class($childNode) !== 'DOMElement') continue;
112 +
113 + // Overwrite id if not a bookstack custom id
114 + if ($childNode->hasAttribute('id')) {
115 + $id = $childNode->getAttribute('id');
116 + if (strpos($id, 'bkmrk') === 0 && array_search($id, $idArray) === false) {
117 + $idArray[] = $id;
118 + continue;
119 + };
120 + }
121 +
122 + // Create an unique id for the element
123 + do {
124 + $id = 'bkmrk-' . substr(uniqid(), -5);
125 + } while ($id == $lastId);
126 + $lastId = $id;
127 +
128 + $childNode->setAttribute('id', $id);
129 + $idArray[] = $id;
130 + }
131 +
132 + // Generate inner html as a string
133 + $html = '';
134 + foreach ($childNodes as $childNode) {
135 + $html .= $doc->saveHTML($childNode);
136 + }
137 +
138 + return $html;
139 + }
140 +
56 public function destroyById($id) 141 public function destroyById($id)
57 { 142 {
58 $page = $this->getById($id); 143 $page = $this->getById($id);
...@@ -99,8 +184,8 @@ class PageRepo ...@@ -99,8 +184,8 @@ class PageRepo
99 */ 184 */
100 public function searchForImage($imageString) 185 public function searchForImage($imageString)
101 { 186 {
102 - $pages = $this->page->where('html', 'like', '%'.$imageString.'%')->get(); 187 + $pages = $this->page->where('html', 'like', '%' . $imageString . '%')->get();
103 - foreach($pages as $page) { 188 + foreach ($pages as $page) {
104 $page->url = $page->getUrl(); 189 $page->url = $page->getUrl();
105 $page->html = ''; 190 $page->html = '';
106 $page->text = ''; 191 $page->text = '';
...@@ -111,14 +196,15 @@ class PageRepo ...@@ -111,14 +196,15 @@ class PageRepo
111 /** 196 /**
112 * Updates a page with any fillable data and saves it into the database. 197 * Updates a page with any fillable data and saves it into the database.
113 * @param Page $page 198 * @param Page $page
114 - * @param $book_id 199 + * @param int $book_id
115 - * @param $data 200 + * @param string $input
116 * @return Page 201 * @return Page
117 */ 202 */
118 - public function updatePage(Page $page, $book_id, $data) 203 + public function updatePage(Page $page, $book_id, $input)
119 { 204 {
120 - $page->fill($data); 205 + $page->fill($input);
121 $page->slug = $this->findSuitableSlug($page->name, $book_id, $page->id); 206 $page->slug = $this->findSuitableSlug($page->name, $book_id, $page->id);
207 + $page->html = $this->formatHtml($input['html']);
122 $page->text = strip_tags($page->html); 208 $page->text = strip_tags($page->html);
123 $page->updated_by = Auth::user()->id; 209 $page->updated_by = Auth::user()->id;
124 $page->save(); 210 $page->save();
...@@ -189,7 +275,7 @@ class PageRepo ...@@ -189,7 +275,7 @@ class PageRepo
189 public function setBookId($bookId, Page $page) 275 public function setBookId($bookId, Page $page)
190 { 276 {
191 $page->book_id = $bookId; 277 $page->book_id = $bookId;
192 - foreach($page->activity as $activity) { 278 + foreach ($page->activity as $activity) {
193 $activity->book_id = $bookId; 279 $activity->book_id = $bookId;
194 $activity->save(); 280 $activity->save();
195 } 281 }
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
11 "dropzone": "^4.0.1", 11 "dropzone": "^4.0.1",
12 "laravel-elixir": "^3.3.1", 12 "laravel-elixir": "^3.3.1",
13 "vue": "^0.12.16", 13 "vue": "^0.12.16",
14 - "vue-resource": "^0.1.16" 14 + "vue-resource": "^0.1.16",
15 + "zeroclipboard": "^2.2.0"
15 } 16 }
16 } 17 }
......
No preview for this file type
1 +window.ZeroClipboard = require('zeroclipboard');
2 +window.ZeroClipboard.config({
3 + swfPath: '/ZeroClipboard.swf'
4 +});
1 5
2 // Global jQuery Elements 6 // Global jQuery Elements
3 $(function () { 7 $(function () {
...@@ -23,6 +27,12 @@ function elemExists(selector) { ...@@ -23,6 +27,12 @@ function elemExists(selector) {
23 return document.querySelector(selector) !== null; 27 return document.querySelector(selector) !== null;
24 } 28 }
25 29
30 +// TinyMCE editor
31 +if(elemExists('#html-editor')) {
32 + var tinyMceOptions = require('./pages/page-form');
33 + tinymce.init(tinyMceOptions);
34 +}
35 +
26 // Vue JS elements 36 // Vue JS elements
27 var Vue = require('vue'); 37 var Vue = require('vue');
28 Vue.use(require('vue-resource')); 38 Vue.use(require('vue-resource'));
......
1 +
2 +module.exports = {
3 + selector: '#html-editor',
4 + content_css: [
5 + '/css/styles.css',
6 + '//fonts.googleapis.com/css?family=Roboto:400,400italic,500,500italic,700,700italic,300italic,100,300'
7 + ],
8 + body_class: 'page-content',
9 + relative_urls: false,
10 + statusbar: false,
11 + menubar: false,
12 + //height: 700,
13 + extended_valid_elements: 'pre[*]',
14 + valid_children: "-div[p|pre|h1|h2|h3|h4|h5|h6|blockquote]",
15 + plugins: "image table textcolor paste link imagetools fullscreen code hr",
16 + toolbar: "code undo | styleselect | hr bold italic underline strikethrough superscript subscript | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | table image link | fullscreen",
17 + content_style: "body {padding-left: 15px !important; padding-right: 15px !important; margin:0!important; margin-left:auto!important;margin-right:auto!important;}",
18 + style_formats: [
19 + {title: "Header 1", format: "h1"},
20 + {title: "Header 2", format: "h2"},
21 + {title: "Header 3", format: "h3"},
22 + {title: "Header 4", format: "h4"},
23 + {title: "Paragraph", format: "p"},
24 + {title: "Blockquote", format: "blockquote"},
25 + {title: "Code Block", icon: "code", format: "pre"}
26 + ],
27 + file_browser_callback: function(field_name, url, type, win) {
28 + ImageManager.show(function(image) {
29 + win.document.getElementById(field_name).value = image.url;
30 + if ("createEvent" in document) {
31 + var evt = document.createEvent("HTMLEvents");
32 + evt.initEvent("change", false, true);
33 + win.document.getElementById(field_name).dispatchEvent(evt);
34 + } else {
35 + win.document.getElementById(field_name).fireEvent("onchange");
36 + }
37 + });
38 + }
39 +};
...\ No newline at end of file ...\ No newline at end of file
...@@ -110,3 +110,20 @@ ...@@ -110,3 +110,20 @@
110 transform: translate3d(0, 0, 0); 110 transform: translate3d(0, 0, 0);
111 } 111 }
112 } 112 }
113 +
114 +@keyframes pointer {
115 + 0% {
116 + transform: translate3d(0, 20px, 0) scale3d(0, 0, 0);
117 + }
118 + 100% {
119 + transform: translate3d(0, 0, 0) scale3d(1, 1, 1);
120 + }
121 +}
122 +
123 +.anim.pointer {
124 + transform-origin: 50% 100%;
125 + animation-name: pointer;
126 + animation-duration: 180ms;
127 + animation-delay: 0s;
128 + animation-timing-function: cubic-bezier(.62, .28, .23, .99);
129 +}
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -85,29 +85,9 @@ $button-border-radius: 2px; ...@@ -85,29 +85,9 @@ $button-border-radius: 2px;
85 display: block; 85 display: block;
86 } 86 }
87 87
88 -// Floating action button 88 +.button.icon {
89 -//.fab { 89 + i {
90 -// $size: 70px; 90 + padding-right: 0;
91 -// button.button { 91 + }
92 -// border-radius: 100%; 92 +}
93 -// width: $size; 93 +
94 -// height: $size;
95 -// font-size: 48px;
96 -// text-align: center;
97 -// margin: 0;
98 -// padding: 0;
99 -// border: 0;
100 -// box-shadow: 0 0 2px 2px #DDD;
101 -// transition: all ease-in-out 160ms;
102 -// i {
103 -// transform: rotate(0deg);
104 -// transition: all ease-in-out 160ms;
105 -// }
106 -// &:hover {
107 -// box-shadow: 0 2px 4px 2px #CCC;
108 -// i {
109 -// transform: rotate(180deg);
110 -// }
111 -// }
112 -// }
113 -//}
......
...@@ -23,38 +23,65 @@ ...@@ -23,38 +23,65 @@
23 } 23 }
24 } 24 }
25 25
26 -// Link hooks & popovers 26 +// Page content pointers
27 -a.link-hook { 27 +.pointer-container {
28 - position: absolute; 28 + position: relative;
29 + display: none;
30 + left: 2%;
31 +}
32 +.pointer {
33 + border: 1px solid #CCC;
29 display: inline-block; 34 display: inline-block;
30 - top: $-xs; 35 + padding: $-xs $-s;
31 - left: -$-l; 36 + border-radius: 4px;
32 - padding-bottom: 30px; 37 + box-shadow: 0 0 8px 1px rgba(212, 209, 209, 0.35);
33 - font-size: 20px; 38 + position: absolute;
34 - line-height: 20px; 39 + top: -60px;
35 - color: #BBB; 40 + background-color:#FFF;
36 - opacity: 0; 41 + &:before {
37 - transform: translate3d(10px, 0, 0); 42 + position: absolute;
38 - transition: all ease-in-out 240ms; 43 + left: 50%;
39 - background-color: transparent; 44 + bottom: -9px;
40 - &:hover { 45 + width: 16px;
41 - color: $primary; 46 + height: 16px;
47 + margin-left: -8px;
48 + content: '';
49 + display: block;
50 + background-color:#FFF;
51 + transform: rotate(45deg);
52 + transform-origin: 50% 50%;
53 + border-bottom: 1px solid #CCC;
54 + border-right: 1px solid #CCC;
55 + z-index: 1;
56 + }
57 + input {
58 + background-color: #FFF;
59 + border: 1px solid #DDD;
60 + color: #666;
61 + width: 180px;
62 + z-index: 40;
63 + }
64 + input, button {
65 + position: relative;
66 + border-radius: 0;
67 + height: 28px;
68 + font-size: 12px;
69 + }
70 + > i {
71 + color: #888;
72 + font-size: 18px;
73 + padding-top: 4px;
74 + }
75 + .button {
76 + line-height: 1;
77 + margin: 0 0 0 -4px;
78 + box-shadow: none;
42 } 79 }
43 } 80 }
81 +
44 h1, h2, h3, h4, h5, h6 { 82 h1, h2, h3, h4, h5, h6 {
45 &:hover a.link-hook { 83 &:hover a.link-hook {
46 opacity: 1; 84 opacity: 1;
47 transform: translate3d(0, 0, 0); 85 transform: translate3d(0, 0, 0);
48 } 86 }
49 } 87 }
50 -
51 -// Side Navigation
52 -.side-nav {
53 - position: fixed;
54 - padding-left: $-m;
55 - opacity: 0.8;
56 - margin-top: $-xxl;
57 - margin-left: 0;
58 - max-width: 240px;
59 - display: none;
60 -}
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
28 </div> 28 </div>
29 </div> 29 </div>
30 <div class="edit-area flex-fill flex"> 30 <div class="edit-area flex-fill flex">
31 - <textarea id="html" name="html" rows="5" 31 + <textarea id="html-editor" name="html" rows="5"
32 @if($errors->has('html')) class="neg" @endif>@if(isset($model) || old('html')){{htmlspecialchars( old('html') ? old('html') : $model->html)}}@endif</textarea> 32 @if($errors->has('html')) class="neg" @endif>@if(isset($model) || old('html')){{htmlspecialchars( old('html') ? old('html') : $model->html)}}@endif</textarea>
33 @if($errors->has('html')) 33 @if($errors->has('html'))
34 <div class="text-neg text-small">{{ $errors->first('html') }}</div> 34 <div class="text-neg text-small">{{ $errors->first('html') }}</div>
...@@ -36,68 +36,4 @@ ...@@ -36,68 +36,4 @@
36 </div> 36 </div>
37 </div> 37 </div>
38 38
39 -
40 -
41 -
42 -
43 -<script>
44 - $(function() {
45 - //ImageManager.show('#image-manager');
46 -
47 - tinymce.init({
48 - selector: '.edit-area textarea',
49 - content_css: [
50 - '/css/app.css',
51 - '//fonts.googleapis.com/css?family=Roboto:400,400italic,500,500italic,700,700italic,300italic,100,300'
52 - ],
53 - body_class: 'page-content',
54 - relative_urls: false,
55 - statusbar: false,
56 - menubar: false,
57 - //height: 700,
58 - extended_valid_elements: 'pre[*]',
59 - plugins: "image table textcolor paste link imagetools fullscreen code hr",
60 - toolbar: "code undo | styleselect | hr bold italic underline strikethrough superscript subscript | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | table image link | fullscreen",
61 - content_style: "body {padding-left: 15px !important; padding-right: 15px !important; margin:0!important; margin-left:auto!important;margin-right:auto!important;}",
62 - style_formats: [
63 - {title: "Header 1", format: "h1"},
64 - {title: "Header 2", format: "h2"},
65 - {title: "Header 3", format: "h3"},
66 - {title: "Header 4", format: "h4"},
67 - {title: "Paragraph", format: "p"},
68 - {title: "Blockquote", format: "blockquote"},
69 - {title: "Code Block", icon: "code", format: "pre"}
70 - ],
71 - file_browser_callback: function(field_name, url, type, win) {
72 - ImageManager.show(function(image) {
73 - win.document.getElementById(field_name).value = image.url;
74 - if ("createEvent" in document) {
75 - var evt = document.createEvent("HTMLEvents");
76 - evt.initEvent("change", false, true);
77 - win.document.getElementById(field_name).dispatchEvent(evt);
78 - } else {
79 - win.document.getElementById(field_name).fireEvent("onchange");
80 - }
81 - });
82 - }
83 -// setup: function(editor) {
84 -// editor.addButton('full', {
85 -// title: 'Expand Editor',
86 -// icon: 'fullscreen',
87 -// onclick: function() {
88 -// var container = $(editor.getContainer()).toggleClass('fullscreen');
89 -// var isFull = container.hasClass('fullscreen');
90 -// var iframe = container.find('iframe').first();
91 -// var height = isFull ? $(window).height()-110 : 600;
92 -// iframe.css('height', height + 'px');
93 -// }
94 -// });
95 -// }
96 - });
97 -
98 -
99 -
100 - });
101 -</script>
102 -
103 <image-manager></image-manager> 39 <image-manager></image-manager>
...\ No newline at end of file ...\ No newline at end of file
......
1 -<h1>{{$page->name}}</h1> 1 +<h1 id="bkmrk-page-title">{{$page->name}}</h1>
2 -@if(count($page->children) > 0) 2 +
3 - <h4 class="text-muted">Sub-pages</h4>
4 - <div class="page-list">
5 - @foreach($page->children as $childPage)
6 - <a href="{{ $childPage->getUrl() }}">{{ $childPage->name }}</a>
7 - @endforeach
8 - </div>
9 -@endif
10 {!! $page->html !!} 3 {!! $page->html !!}
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -37,22 +37,31 @@ ...@@ -37,22 +37,31 @@
37 <div class="row"> 37 <div class="row">
38 <div class="col-md-9"> 38 <div class="col-md-9">
39 <div class="page-content anim fadeIn"> 39 <div class="page-content anim fadeIn">
40 +
41 + <div class="pointer-container" id="pointer">
42 + <div class="pointer anim">
43 + <i class="zmdi zmdi-link"></i>
44 + <input readonly="readonly" type="text" placeholder="url">
45 + <button class="button icon" title="Copy Link" data-clipboard-text=""><i class="zmdi zmdi-copy"></i></button>
46 + </div>
47 + </div>
48 +
40 @include('pages/page-display') 49 @include('pages/page-display')
50 +
41 <hr> 51 <hr>
52 +
42 <p class="text-muted small"> 53 <p class="text-muted small">
43 Created {{$page->created_at->diffForHumans()}} @if($page->createdBy) by {{$page->createdBy->name}} @endif 54 Created {{$page->created_at->diffForHumans()}} @if($page->createdBy) by {{$page->createdBy->name}} @endif
44 <br> 55 <br>
45 Last Updated {{$page->updated_at->diffForHumans()}} @if($page->createdBy) by {{$page->updatedBy->name}} @endif 56 Last Updated {{$page->updated_at->diffForHumans()}} @if($page->createdBy) by {{$page->updatedBy->name}} @endif
46 </p> 57 </p>
58 +
47 </div> 59 </div>
48 </div> 60 </div>
49 <div class="col-md-3"> 61 <div class="col-md-3">
62 +
50 @include('pages/sidebar-tree-list', ['book' => $book]) 63 @include('pages/sidebar-tree-list', ['book' => $book])
51 - <div class="side-nav faded"> 64 +
52 - <h4>Page Navigation</h4>
53 - <ul class="page-nav-list">
54 - </ul>
55 - </div>
56 </div> 65 </div>
57 </div> 66 </div>
58 </div> 67 </div>
...@@ -64,53 +73,53 @@ ...@@ -64,53 +73,53 @@
64 <script> 73 <script>
65 $(document).ready(function() { 74 $(document).ready(function() {
66 75
67 - // Set up document navigation
68 - var pageNav = $('.page-nav-list');
69 - var pageContent = $('.page-content');
70 - var headers = pageContent.find('h1, h2, h3, h4, h5, h6');
71 - if(headers.length > 5) {
72 - headers.each(function() {
73 - var header = $(this);
74 - var tag = header.prop('tagName');
75 - var listElem = $('<li></li>').addClass('nav-'+tag);
76 - var link = $('<a></a>').text(header.text().trim()).attr('href', '#');
77 - listElem.append(link);
78 - pageNav.append(listElem);
79 - link.click(function(e) {
80 - e.preventDefault();
81 - header.smoothScrollTo();
82 - })
83 - });
84 - $('.side-nav').fadeIn();
85 - } else {
86 - $('.side-nav').hide();
87 - }
88 -
89 76
90 - // Set up link hooks 77 + // Set up pointer
78 + var $pointer = $('#pointer').detach();
91 var pageId = {{$page->id}}; 79 var pageId = {{$page->id}};
92 - headers.each(function() { 80 + var isSelection = false;
93 - var text = $(this).text().trim(); 81 +
94 - var link = '/link/' + pageId + '#' + encodeURIComponent(text); 82 + $pointer.find('input').click(function(e){$(this).select();e.stopPropagation();});
95 - var linkHook = $('<a class="link-hook"><i class="zmdi zmdi-link"></i></a>') 83 + new ZeroClipboard( $pointer.find('button').first()[0] );
96 - .attr({"data-content": link, href: link, target: '_blank'}); 84 +
97 - linkHook.click(function(e) { 85 + $(document.body).find('*').on('click focus', function(e) {
98 - e.preventDefault(); 86 + if(!isSelection) {
99 - goToText(text); 87 + $pointer.detach();
88 + }
100 }); 89 });
101 - $(this).append(linkHook); 90 +
91 + $('.page-content [id^="bkmrk"]').on('mouseup keyup', function(e) {
92 + var selection = window.getSelection();
93 + if(selection.toString().length === 0) return;
94 + // Show pointer and set link
95 + var $elem = $(this);
96 + var link = window.location.protocol + "//" + window.location.host + '/link/' + pageId + '#' + $elem.attr('id');
97 + $pointer.find('input').val(link);
98 + $pointer.find('button').first().attr('data-clipboard-text', link);
99 + $elem.before($pointer);
100 + $pointer.show();
101 + e.stopPropagation();
102 +
103 + isSelection = true;
104 + setTimeout(function() {
105 + isSelection = false;
106 + }, 100);
102 }); 107 });
103 108
104 function goToText(text) { 109 function goToText(text) {
110 + var idElem = $('.page-content').find('#' + text).first();
111 + if(idElem.length !== 0) {
112 + idElem.smoothScrollTo();
113 + } else {
105 $('.page-content').find(':contains("'+text+'")').smoothScrollTo(); 114 $('.page-content').find(':contains("'+text+'")').smoothScrollTo();
106 } 115 }
116 + }
107 117
108 if(window.location.hash) { 118 if(window.location.hash) {
109 var text = window.location.hash.replace(/\%20/g, ' ').substr(1); 119 var text = window.location.hash.replace(/\%20/g, ' ').substr(1);
110 goToText(text); 120 goToText(text);
111 } 121 }
112 122
113 - //$('[data-toggle="popover"]').popover()
114 }); 123 });
115 </script> 124 </script>
116 125
......
...@@ -3,14 +3,12 @@ ...@@ -3,14 +3,12 @@
3 <head> 3 <head>
4 <title>BookStack</title> 4 <title>BookStack</title>
5 <meta name="viewport" content="width=device-width"> 5 <meta name="viewport" content="width=device-width">
6 - <link rel="stylesheet" href="/css/app.css"> 6 + <link rel="stylesheet" href="/css/styles.css">
7 <link href='//fonts.googleapis.com/css?family=Roboto:400,400italic,500,500italic,700,700italic,300italic,100,300' rel='stylesheet' type='text/css'> 7 <link href='//fonts.googleapis.com/css?family=Roboto:400,400italic,500,500italic,700,700italic,300italic,100,300' rel='stylesheet' type='text/css'>
8 <link rel="stylesheet" href="/bower/material-design-iconic-font/dist/css/material-design-iconic-font.min.css"> 8 <link rel="stylesheet" href="/bower/material-design-iconic-font/dist/css/material-design-iconic-font.min.css">
9 9
10 <!-- Scripts --> 10 <!-- Scripts -->
11 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script> 11 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
12 - <script src="/js/common.js"></script>
13 -
14 </head> 12 </head>
15 <body class="@yield('body-class')"> 13 <body class="@yield('body-class')">
16 14
......