Toggle navigation
Toggle navigation
This project
Loading...
Sign in
Зуев Егор
/
wiki.dev
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Snippets
Network
Create a new issue
Commits
Issue Boards
Files
Commits
Network
Compare
Branches
Tags
Authored by
Dan Brown
2016-03-09 22:32:07 +0000
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
Commit
59ce228c2e01288846d823d563e31a1ba357b63d
59ce228c
1 parent
1d6137f7
Moved page editing to angular controller and started work on update drafts
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
202 additions
and
32 deletions
app/Http/Controllers/PageController.php
app/Http/routes.php
app/Page.php
app/PageRevision.php
app/Repos/PageRepo.php
database/migrations/2016_03_09_203143_add_page_revision_types.php
resources/assets/js/controllers.js
resources/assets/js/directives.js
resources/assets/js/global.js
resources/assets/js/pages/page-form.js
resources/views/pages/create.blade.php
resources/views/pages/edit.blade.php
resources/views/pages/form.blade.php
resources/views/pages/revisions.blade.php
app/Http/Controllers/PageController.php
View file @
59ce228
...
...
@@ -143,6 +143,23 @@ class PageController extends Controller
}
/**
* Save a draft update as a revision.
* @param Request $request
* @param $pageId
* @return \Illuminate\Http\JsonResponse
*/
public
function
saveUpdateDraft
(
Request
$request
,
$pageId
)
{
$this
->
validate
(
$request
,
[
'name'
=>
'required|string|max:255'
]);
$page
=
$this
->
pageRepo
->
getById
(
$pageId
);
$this
->
checkOwnablePermission
(
'page-update'
,
$page
);
$this
->
pageRepo
->
saveUpdateDraft
(
$page
,
$request
->
only
([
'name'
,
'html'
]));
return
response
()
->
json
([
'status'
=>
'success'
,
'message'
=>
'Draft successfully saved'
]);
}
/**
* Redirect from a special link url which
* uses the page id rather than the name.
* @param $pageId
...
...
app/Http/routes.php
View file @
59ce228
...
...
@@ -75,6 +75,9 @@ Route::group(['middleware' => 'auth'], function () {
Route
::
delete
(
'/{imageId}'
,
'ImageController@destroy'
);
});
// Ajax routes
Route
::
put
(
'/ajax/page/{id}/save-draft'
,
'PageController@saveUpdateDraft'
);
// Links
Route
::
get
(
'/link/{id}'
,
'PageController@redirectFromLink'
);
...
...
app/Page.php
View file @
59ce228
...
...
@@ -34,7 +34,7 @@ class Page extends Entity
public
function
revisions
()
{
return
$this
->
hasMany
(
'BookStack\PageRevision'
)
->
orderBy
(
'created_at'
,
'desc'
);
return
$this
->
hasMany
(
'BookStack\PageRevision'
)
->
where
(
'type'
,
'='
,
'version'
)
->
orderBy
(
'created_at'
,
'desc'
);
}
public
function
getUrl
()
...
...
app/PageRevision.php
View file @
59ce228
<?php
namespace
BookStack
;
<?php
namespace
BookStack
;
use
Illuminate\Database\Eloquent\Model
;
...
...
@@ -8,16 +6,28 @@ class PageRevision extends Model
{
protected
$fillable
=
[
'name'
,
'html'
,
'text'
];
/**
* Get the user that created the page revision
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public
function
createdBy
()
{
return
$this
->
belongsTo
(
'BookStack\User'
,
'created_by'
);
}
/**
* Get the page this revision originates from.
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public
function
page
()
{
return
$this
->
belongsTo
(
'BookStack\Page'
);
}
/**
* Get the url for this revision.
* @return string
*/
public
function
getUrl
()
{
return
$this
->
page
->
getUrl
()
.
'/revisions/'
.
$this
->
id
;
...
...
app/Repos/PageRepo.php
View file @
59ce228
...
...
@@ -4,6 +4,7 @@
use
Activity
;
use
BookStack\Book
;
use
BookStack\Exceptions\NotFoundException
;
use
DOMDocument
;
use
Illuminate\Support\Str
;
use
BookStack\Page
;
use
BookStack\PageRevision
;
...
...
@@ -66,9 +67,10 @@ class PageRepo extends EntityRepo
public
function
findPageUsingOldSlug
(
$pageSlug
,
$bookSlug
)
{
$revision
=
$this
->
pageRevision
->
where
(
'slug'
,
'='
,
$pageSlug
)
->
whereHas
(
'page'
,
function
(
$query
)
{
->
whereHas
(
'page'
,
function
(
$query
)
{
$this
->
restrictionService
->
enforcePageRestrictions
(
$query
);
})
->
where
(
'type'
,
'='
,
'version'
)
->
where
(
'book_slug'
,
'='
,
$bookSlug
)
->
orderBy
(
'created_at'
,
'desc'
)
->
with
(
'page'
)
->
first
();
return
$revision
!==
null
?
$revision
->
page
:
null
;
...
...
@@ -100,8 +102,8 @@ class PageRepo extends EntityRepo
* Save a new page into the system.
* Input validation must be done beforehand.
* @param array $input
* @param Book
$book
* @param int
$chapterId
* @param Book $book
* @param int $chapterId
* @return Page
*/
public
function
saveNew
(
array
$input
,
Book
$book
,
$chapterId
=
null
)
...
...
@@ -128,9 +130,9 @@ class PageRepo extends EntityRepo
*/
protected
function
formatHtml
(
$htmlText
)
{
if
(
$htmlText
==
''
)
return
$htmlText
;
if
(
$htmlText
==
''
)
return
$htmlText
;
libxml_use_internal_errors
(
true
);
$doc
=
new
\
DOMDocument
();
$doc
=
new
DOMDocument
();
$doc
->
loadHTML
(
mb_convert_encoding
(
$htmlText
,
'HTML-ENTITIES'
,
'UTF-8'
));
$container
=
$doc
->
documentElement
;
...
...
@@ -239,8 +241,8 @@ class PageRepo extends EntityRepo
/**
* Updates a page with any fillable data and saves it into the database.
* @param Page
$page
* @param int
$book_id
* @param Page $page
* @param int $book_id
* @param string $input
* @return Page
*/
...
...
@@ -297,6 +299,7 @@ class PageRepo extends EntityRepo
$revision
->
book_slug
=
$page
->
book
->
slug
;
$revision
->
created_by
=
auth
()
->
user
()
->
id
;
$revision
->
created_at
=
$page
->
updated_at
;
$revision
->
type
=
'version'
;
$revision
->
save
();
// Clear old revisions
if
(
$this
->
pageRevision
->
where
(
'page_id'
,
'='
,
$page
->
id
)
->
count
()
>
50
)
{
...
...
@@ -307,6 +310,36 @@ class PageRepo extends EntityRepo
}
/**
* Save a page update draft.
* @param Page $page
* @param array $data
* @return PageRevision
*/
public
function
saveUpdateDraft
(
Page
$page
,
$data
=
[])
{
$userId
=
auth
()
->
user
()
->
id
;
$drafts
=
$this
->
pageRevision
->
where
(
'created_by'
,
'='
,
$userId
)
->
where
(
'type'
,
'update_draft'
)
->
where
(
'page_id'
,
'='
,
$page
->
id
)
->
orderBy
(
'created_at'
,
'desc'
)
->
get
();
if
(
$drafts
->
count
()
>
0
)
{
$draft
=
$drafts
->
first
();
}
else
{
$draft
=
$this
->
pageRevision
->
newInstance
();
$draft
->
page_id
=
$page
->
id
;
$draft
->
slug
=
$page
->
slug
;
$draft
->
book_slug
=
$page
->
book
->
slug
;
$draft
->
created_by
=
$userId
;
$draft
->
type
=
'update_draft'
;
}
$draft
->
fill
(
$data
);
$draft
->
save
();
return
$draft
;
}
/**
* Gets a single revision via it's id.
* @param $id
* @return mixed
...
...
@@ -333,7 +366,7 @@ class PageRepo extends EntityRepo
/**
* Changes the related book for the specified page.
* Changes the book id of any relations to the page that store the book id.
* @param int
$bookId
* @param int $bookId
* @param Page $page
* @return Page
*/
...
...
database/migrations/2016_03_09_203143_add_page_revision_types.php
0 → 100644
View file @
59ce228
<?php
use
Illuminate\Database\Schema\Blueprint
;
use
Illuminate\Database\Migrations\Migration
;
class
AddPageRevisionTypes
extends
Migration
{
/**
* Run the migrations.
*
* @return void
*/
public
function
up
()
{
Schema
::
table
(
'page_revisions'
,
function
(
Blueprint
$table
)
{
$table
->
string
(
'type'
)
->
default
(
'version'
);
$table
->
index
(
'type'
);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public
function
down
()
{
Schema
::
table
(
'page_revisions'
,
function
(
Blueprint
$table
)
{
$table
->
dropColumn
(
'type'
);
});
}
}
resources/assets/js/controllers.js
View file @
59ce228
...
...
@@ -213,4 +213,49 @@ module.exports = function (ngApp, events) {
}]);
ngApp
.
controller
(
'PageEditController'
,
[
'$scope'
,
'$http'
,
'$attrs'
,
'$interval'
,
function
(
$scope
,
$http
,
$attrs
,
$interval
)
{
$scope
.
editorOptions
=
require
(
'./pages/page-form'
);
$scope
.
editorHtml
=
''
;
$scope
.
draftText
=
''
;
var
pageId
=
Number
(
$attrs
.
pageId
);
var
isEdit
=
pageId
!==
0
;
if
(
isEdit
)
{
startAutoSave
();
}
$scope
.
editorChange
=
function
()
{
$scope
.
draftText
=
''
;
}
function
startAutoSave
()
{
var
currentTitle
=
$
(
'#name'
).
val
();
var
currentHtml
=
$scope
.
editorHtml
;
console
.
log
(
'Starting auto save'
);
$interval
(()
=>
{
var
newTitle
=
$
(
'#name'
).
val
();
var
newHtml
=
$scope
.
editorHtml
;
if
(
newTitle
!==
currentTitle
||
newHtml
!==
currentHtml
)
{
currentHtml
=
newHtml
;
currentTitle
=
newTitle
;
saveDraftUpdate
(
newTitle
,
newHtml
);
}
},
1000
*
5
);
}
function
saveDraftUpdate
(
title
,
html
)
{
$http
.
put
(
'/ajax/page/'
+
pageId
+
'/save-draft'
,
{
name
:
title
,
html
:
html
}).
then
((
responseData
)
=>
{
$scope
.
draftText
=
'Draft saved'
})
}
}]);
};
\ No newline at end of file
...
...
resources/assets/js/directives.js
View file @
59ce228
...
...
@@ -162,5 +162,31 @@ module.exports = function (ngApp, events) {
};
}]);
ngApp
.
directive
(
'tinymce'
,
[
function
()
{
return
{
restrict
:
'A'
,
scope
:
{
tinymce
:
'='
,
ngModel
:
'='
,
ngChange
:
'='
},
link
:
function
(
scope
,
element
,
attrs
)
{
function
tinyMceSetup
(
editor
)
{
editor
.
on
(
'keyup'
,
(
e
)
=>
{
var
content
=
editor
.
getContent
();
scope
.
$apply
(()
=>
{
scope
.
ngModel
=
content
;
});
scope
.
ngChange
(
content
);
});
}
scope
.
tinymce
.
extraSetups
.
push
(
tinyMceSetup
);
tinymce
.
init
(
scope
.
tinymce
);
}
}
}])
};
\ No newline at end of file
...
...
resources/assets/js/global.js
View file @
59ce228
...
...
@@ -119,11 +119,5 @@ function elemExists(selector) {
return
document
.
querySelector
(
selector
)
!==
null
;
}
// TinyMCE editor
if
(
elemExists
(
'#html-editor'
))
{
var
tinyMceOptions
=
require
(
'./pages/page-form'
);
tinymce
.
init
(
tinyMceOptions
);
}
// Page specific items
require
(
'./pages/page-show'
);
\ No newline at end of file
require
(
'./pages/page-show'
);
...
...
resources/assets/js/pages/page-form.js
View file @
59ce228
module
.
exports
=
{
var
mceOptions
=
module
.
exports
=
{
selector
:
'#html-editor'
,
content_css
:
[
'/css/styles.css'
...
...
@@ -51,8 +51,15 @@ module.exports = {
args
.
content
=
''
;
}
},
extraSetups
:
[],
setup
:
function
(
editor
)
{
console
.
log
(
mceOptions
.
extraSetups
);
for
(
var
i
=
0
;
i
<
mceOptions
.
extraSetups
.
length
;
i
++
)
{
mceOptions
.
extraSetups
[
i
](
editor
);
}
(
function
()
{
var
wrap
;
...
...
resources/views/pages/create.blade.php
View file @
59ce228
...
...
@@ -8,7 +8,7 @@
@section('content')
<div
class=
"flex-fill flex"
ng-non-bindable
>
<div
class=
"flex-fill flex"
>
<form
action=
"{{$book->getUrl() . '/page'}}"
method=
"POST"
class=
"flex flex-fill"
>
@include('pages/form')
@if($chapter)
...
...
resources/views/pages/edit.blade.php
View file @
59ce228
...
...
@@ -8,8 +8,8 @@
@section('content')
<div
class=
"flex-fill flex"
ng-non-bindable
>
<form
action=
"{{$page->getUrl()}}"
method=
"POST"
class=
"flex flex-fill"
>
<div
class=
"flex-fill flex"
>
<form
action=
"{{$page->getUrl()}}"
data-page-id=
"{{ $page->id }}"
method=
"POST"
class=
"flex flex-fill"
>
<input
type=
"hidden"
name=
"_method"
value=
"PUT"
>
@include('pages/form', ['model' => $page])
</form>
...
...
resources/views/pages/form.blade.php
View file @
59ce228
<div
class=
"page-editor flex-fill flex"
ng-
non-bindable
>
<div
class=
"page-editor flex-fill flex"
ng-
controller=
"PageEditController"
page-id=
"{{ $model->id or 0 }}"
>
{{ csrf_field() }}
<div
class=
"faded-small toolbar"
>
...
...
@@ -12,7 +12,10 @@
<a
onclick=
"$('body>header').slideToggle();"
class=
"text-button text-primary"
><i
class=
"zmdi zmdi-swap-vertical"
></i>
Toggle Header
</a>
</div>
</div>
<div
class=
"col-sm-8 faded"
>
<div
class=
"col-sm-4 faded text-center"
>
<span
ng-bind=
"draftText"
></span>
</div>
<div
class=
"col-sm-4 faded"
>
<div
class=
"action-buttons"
>
<a
href=
"{{ back()->getTargetUrl() }}"
class=
"text-button text-primary"
><i
class=
"zmdi zmdi-close"
></i>
Cancel
</a>
<button
type=
"submit"
id=
"save-button"
class=
"text-button text-pos"
><i
class=
"zmdi zmdi-floppy"
></i>
Save Page
</button>
...
...
@@ -22,13 +25,13 @@
</div>
</div>
<div
class=
"title-input page-title clearfix"
>
<div
class=
"title-input page-title clearfix"
ng-non-bindable
>
<div
class=
"input"
>
@include('form/text', ['name' => 'name', 'placeholder' => 'Page Title'])
</div>
</div>
<div
class=
"edit-area flex-fill flex"
>
<textarea
id=
"html-editor"
name=
"html"
rows=
"5"
<textarea
id=
"html-editor"
tinymce=
"editorOptions"
ng-change=
"editorChange"
ng-model=
"editorHtml"
name=
"html"
rows=
"5"
@
if
($
errors-
>
has('html')) class="neg" @endif>@if(isset($model) || old('html')){{htmlspecialchars( old('html') ? old('html') : $model->html)}}@endif
</textarea>
@if($errors->has('html'))
<div
class=
"text-neg text-small"
>
{{ $errors->first('html') }}
</div>
...
...
resources/views/pages/revisions.blade.php
View file @
59ce228
...
...
@@ -24,10 +24,10 @@
<table
class=
"table"
>
<tr>
<th>
Name
</th>
<th
colspan=
"2"
>
Created By
</th>
<th>
Revision Date
</th>
<th>
Actions
</th>
<th
width=
"40%"
>
Name
</th>
<th
colspan=
"2"
width=
"20%"
>
Created By
</th>
<th
width=
"20%"
>
Revision Date
</th>
<th
width=
"20%"
>
Actions
</th>
</tr>
@foreach($page->revisions as $revision)
<tr>
...
...
@@ -38,7 +38,7 @@
@endif
</td>
<td>
@if($revision->createdBy) {{$revision->createdBy->name}} @else Deleted User @endif
</td>
<td><small>
{{$revision->created_at->format('jS F, Y H:i:s')}} ({{$revision->created_at->diffForHumans()}})
</small></td>
<td><small>
{{$revision->created_at->format('jS F, Y H:i:s')}}
<br>
({{$revision->created_at->diffForHumans()}})
</small></td>
<td>
<a
href=
"{{$revision->getUrl()}}"
target=
"_blank"
>
Preview
</a>
<span
class=
"text-muted"
>
|
</span>
...
...
Please
register
or
sign in
to post a comment