Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wiki-js
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
1
Issues
1
List
Board
Labels
Milestones
Merge Requests
1
Merge Requests
1
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
wiki-js
Commits
4625a302
Commit
4625a302
authored
Jan 02, 2017
by
NGPixel
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Video player modal + provider match
parent
dab4a970
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
168 additions
and
38 deletions
+168
-38
README.md
README.md
+1
-0
app.css
assets/css/app.css
+0
-0
app.js
assets/js/app.js
+0
-0
alerts.js
client/js/components/alerts.js
+3
-3
editor-video.js
client/js/components/editor-video.js
+50
-0
editor.js
client/js/components/editor.js
+23
-21
pages.js
controllers/pages.js
+4
-4
gulpfile.js
gulpfile.js
+1
-1
local.js
libs/local.js
+1
-0
markdown.js
libs/markdown.js
+44
-0
uploads.js
libs/uploads.js
+1
-1
alerts.pug
views/common/alerts.pug
+6
-8
editor-video.pug
views/modals/editor-video.pug
+29
-0
create.pug
views/pages/create.pug
+3
-0
edit.pug
views/pages/edit.pug
+2
-0
No files found.
README.md
View file @
4625a302
...
...
@@ -49,6 +49,7 @@
-
[
]
Links
-
[
x
]
Image Selection modal
-
[
x
]
File Selection modal
-
[
x
]
Video player
-
[
x
]
Inline Code
-
[
x
]
Code Editor modal
-
[
]
Table Editor
...
...
assets/css/app.css
View file @
4625a302
This source diff could not be displayed because it is too large. You can
view the blob
instead.
assets/js/app.js
View file @
4625a302
This diff is collapsed.
Click to expand it.
client/js/components/alerts.js
View file @
4625a302
...
...
@@ -42,7 +42,7 @@ class Alerts {
let
nAlert
=
_
.
defaults
(
options
,
{
_uid
:
self
.
uidNext
,
class
:
'i
s-i
nfo'
,
class
:
'info'
,
message
:
'---'
,
sticky
:
false
,
title
:
'---'
...
...
@@ -68,7 +68,7 @@ class Alerts {
*/
pushError
(
title
,
message
)
{
this
.
push
({
class
:
'
is-dange
r'
,
class
:
'
erro
r'
,
message
,
sticky
:
false
,
title
...
...
@@ -83,7 +83,7 @@ class Alerts {
*/
pushSuccess
(
title
,
message
)
{
this
.
push
({
class
:
'
is-
success'
,
class
:
'success'
,
message
,
sticky
:
false
,
title
...
...
client/js/components/editor-video.js
0 → 100644
View file @
4625a302
const
videoRules
=
{
'youtube'
:
new
RegExp
(
/
(?:(?:
youtu
\.
be
\/
|v
\/
|vi
\/
|u
\/\w\/
|embed
\/)
|
(?:(?:
watch
)?\?
v
(?:
i
)?
=|
\&
v
(?:
i
)?
=
))([^
#
\&\?]
*
)
.*/
,
'i'
),
'vimeo'
:
new
RegExp
(
/vimeo.com
\/(?:
channels
\/(?:\w
+
\/)?
|groups
\/(?:[^\/]
*
)\/
videos
\/
|album
\/(?:\d
+
)\/
video
\/
|
)(\d
+
)(?:
$|
\/
|
\?)
/
,
'i'
),
'dailymotion'
:
new
RegExp
(
/
(?:
dailymotion
\.
com
(?:\/
embed
)?(?:\/
video|
\/
hub
)
|dai
\.
ly
)\/([
0-9a-z
]
+
)(?:[\-
_0-9a-zA-Z
]
+
(?:
#video=
)?([
a-z0-9
]
+
)?)?
/
,
'i'
)
};
// Vue Video instance
let
vueVideo
=
new
Vue
({
el
:
'#modal-editor-video'
,
data
:
{
link
:
''
},
methods
:
{
open
:
(
ev
)
=>
{
$
(
'#modal-editor-video'
).
addClass
(
'is-active'
);
$
(
'#modal-editor-video input'
).
focus
();
},
cancel
:
(
ev
)
=>
{
mdeModalOpenState
=
false
;
$
(
'#modal-editor-video'
).
removeClass
(
'is-active'
);
vueVideo
.
link
=
''
;
},
insertVideo
:
(
ev
)
=>
{
if
(
mde
.
codemirror
.
doc
.
somethingSelected
())
{
mde
.
codemirror
.
execCommand
(
'singleSelection'
);
}
// Guess video type
let
videoType
=
_
.
findKey
(
videoRules
,
(
vr
)
=>
{
return
vr
.
test
(
vueVideo
.
link
);
});
if
(
_
.
isNil
(
videoType
))
{
videoType
=
'video'
;
}
// Insert video tag
let
videoText
=
'[video]('
+
vueVideo
.
link
+
'){.'
+
videoType
+
'}
\
n'
;
mde
.
codemirror
.
doc
.
replaceSelection
(
videoText
);
vueVideo
.
cancel
();
}
}
});
\ No newline at end of file
client/js/components/editor.js
View file @
4625a302
...
...
@@ -14,6 +14,7 @@ if($('#mk-editor').length === 1) {
//=include editor-image.js
//=include editor-file.js
//=include editor-video.js
//=include editor-codeblock.js
var
mde
=
new
SimpleMDE
({
...
...
@@ -70,7 +71,7 @@ if($('#mk-editor').length === 1) {
{
name
:
"unordered-list"
,
action
:
SimpleMDE
.
toggleUnorderedList
,
className
:
"icon-
list-ul
"
,
className
:
"icon-
th-list
"
,
title
:
"Bullet List"
,
},
{
...
...
@@ -98,7 +99,7 @@ if($('#mk-editor').length === 1) {
vueImage
.
open
();
}
},
className
:
"icon-image
3
"
,
className
:
"icon-image"
,
title
:
"Insert Image"
,
},
{
...
...
@@ -108,15 +109,15 @@ if($('#mk-editor').length === 1) {
vueFile
.
open
();
}
},
className
:
"icon-
file-text-o
"
,
className
:
"icon-
paper
"
,
title
:
"Insert File"
,
},
{
name
:
"video"
,
action
:
(
editor
)
=>
{
/*
if(!mdeModalOpenState) {
vue
File
.open();
}
*/
if
(
!
mdeModalOpenState
)
{
vue
Video
.
open
();
}
},
className
:
"icon-video-camera2"
,
title
:
"Insert Video Player"
,
...
...
@@ -180,21 +181,6 @@ if($('#mk-editor').length === 1) {
//-> Save
$
(
'.btn-edit-save, .btn-create-save'
).
on
(
'click'
,
(
ev
)
=>
{
saveCurrentDocument
(
ev
);
});
$
(
window
).
bind
(
'keydown'
,
(
ev
)
=>
{
if
(
ev
.
ctrlKey
||
ev
.
metaKey
)
{
switch
(
String
.
fromCharCode
(
ev
.
which
).
toLowerCase
())
{
case
's'
:
ev
.
preventDefault
();
saveCurrentDocument
(
ev
);
break
;
}
}
});
let
saveCurrentDocument
=
(
ev
)
=>
{
$
.
ajax
(
window
.
location
.
href
,
{
data
:
{
...
...
@@ -211,6 +197,21 @@ if($('#mk-editor').length === 1) {
},
(
rXHR
,
rStatus
,
err
)
=>
{
alerts
.
pushError
(
'Something went wrong'
,
'Save operation failed.'
);
});
};
$
(
'.btn-edit-save, .btn-create-save'
).
on
(
'click'
,
(
ev
)
=>
{
saveCurrentDocument
(
ev
);
});
$
(
window
).
bind
(
'keydown'
,
(
ev
)
=>
{
if
(
ev
.
ctrlKey
||
ev
.
metaKey
)
{
switch
(
String
.
fromCharCode
(
ev
.
which
).
toLowerCase
())
{
case
's'
:
ev
.
preventDefault
();
saveCurrentDocument
(
ev
);
break
;
}
}
});
}
\ No newline at end of file
controllers/pages.js
View file @
4625a302
...
...
@@ -43,9 +43,9 @@ router.put('/edit/*', (req, res, next) => {
let
safePath
=
entries
.
parsePath
(
_
.
replace
(
req
.
path
,
'/edit'
,
''
));
entries
.
update
(
safePath
,
req
.
body
.
markdown
).
then
(()
=>
{
res
.
json
({
re
turn
re
s
.
json
({
ok
:
true
});
})
||
true
;
}).
catch
((
err
)
=>
{
res
.
json
({
ok
:
false
,
...
...
@@ -105,9 +105,9 @@ router.put('/create/*', (req, res, next) => {
let
safePath
=
entries
.
parsePath
(
_
.
replace
(
req
.
path
,
'/create'
,
''
));
entries
.
create
(
safePath
,
req
.
body
.
markdown
).
then
(()
=>
{
res
.
json
({
re
turn
re
s
.
json
({
ok
:
true
});
})
||
true
;
}).
catch
((
err
)
=>
{
res
.
json
({
ok
:
false
,
...
...
gulpfile.js
View file @
4625a302
...
...
@@ -196,7 +196,7 @@ gulp.task('dev', function() {
return
run
(
'default'
);
})
})
;
/**
* TASK - Creates deployment packages
...
...
libs/local.js
View file @
4625a302
...
...
@@ -160,6 +160,7 @@ module.exports = {
*
* @param {String} f The filename
* @param {String} fld The containing folder
* @param {boolean} isImage Indicates if image
* @return {Promise<String>} Promise of the accepted filename
*/
validateUploadsFilename
(
f
,
fld
,
isImage
)
{
...
...
libs/markdown.js
View file @
4625a302
...
...
@@ -58,6 +58,31 @@ mkdown.renderer.rules.emoji = function(token, idx) {
return
'<i class="twa twa-'
+
_
.
replace
(
token
[
idx
].
markup
,
/_/g
,
'-'
)
+
'"></i>'
;
};
// Video rules
const
videoRules
=
[
{
selector
:
'a.youtube'
,
regexp
:
new
RegExp
(
/
(?:(?:
youtu
\.
be
\/
|v
\/
|vi
\/
|u
\/\w\/
|embed
\/)
|
(?:(?:
watch
)?\?
v
(?:
i
)?
=|
\&
v
(?:
i
)?
=
))([^
#
\&\?]
*
)
.*/
,
'i'
),
output
:
'<iframe width="640" height="360" src="https://www.youtube.com/embed/{0}?rel=0" frameborder="0" allowfullscreen></iframe>'
},
{
selector
:
'a.vimeo'
,
regexp
:
new
RegExp
(
/vimeo.com
\/(?:
channels
\/(?:\w
+
\/)?
|groups
\/(?:[^\/]
*
)\/
videos
\/
|album
\/(?:\d
+
)\/
video
\/
|
)(\d
+
)(?:
$|
\/
|
\?)
/
,
'i'
),
output
:
'<iframe src="https://player.vimeo.com/video/{0}" width="640" height="360" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>'
},
{
selector
:
'a.dailymotion'
,
regexp
:
new
RegExp
(
/
(?:
dailymotion
\.
com
(?:\/
embed
)?(?:\/
video|
\/
hub
)
|dai
\.
ly
)\/([
0-9a-z
]
+
)(?:[\-
_0-9a-zA-Z
]
+
(?:
#video=
)?([
a-z0-9
]
+
)?)?
/
,
'i'
),
output
:
'<iframe width="640" height="360" src="//www.dailymotion.com/embed/video/{0}?endscreen-enable=false" frameborder="0" allowfullscreen></iframe>'
},
{
selector
:
'a.video'
,
regexp
:
false
,
output
:
'<video width="640" height="360" controls preload="metadata"><source src="{0}" type="video/mp4"></video>'
}
]
/**
* Parse markdown content and build TOC tree
*
...
...
@@ -204,6 +229,25 @@ const parseContent = (content) => {
});
});
// Replace video links with embeds
_
.
forEach
(
videoRules
,
(
vrule
)
=>
{
cr
(
vrule
.
selector
).
each
((
i
,
elm
)
=>
{
let
originLink
=
cr
(
elm
).
attr
(
'href'
);
if
(
vrule
.
regexp
)
{
let
vidMatches
=
originLink
.
match
(
vrule
.
regexp
);
if
((
vidMatches
&&
_
.
isArray
(
vidMatches
)))
{
vidMatches
=
_
.
filter
(
vidMatches
,
(
f
)
=>
{
return
f
&&
_
.
isString
(
f
);
});
originLink
=
_
.
last
(
vidMatches
);
}
}
let
processedLink
=
_
.
replace
(
vrule
.
output
,
'{0}'
,
originLink
);
cr
(
elm
).
replaceWith
(
processedLink
);
});
});
output
=
cr
.
html
();
return
output
;
...
...
libs/uploads.js
View file @
4625a302
...
...
@@ -222,7 +222,7 @@ module.exports = {
destFileStream
.
on
(
'finish'
,
()
=>
{
resolve
(
true
);
})
})
;
rq
.
pipe
(
destFileStream
);
...
...
views/common/alerts.pug
View file @
4625a302
#alerts
ul
template(v-for="aItem in children", track-by='_uid')
.notification
(v-bind:class='aItem.class')
li
(v-bind:class='aItem.class')
button.delete(v-on:click='acknowledge(aItem._uid)')
h3 {{ aItem.title }}
span {{ aItem.message }}
if appflash.length > 0
script(type='text/javascript')
| var alertsData =
!= JSON.stringify(appflash)
| ;
script(type='text/javascript').
var alertsData = !{JSON.stringify(appflash)};
else
script(type='text/javascript')
| var alertsData = [];
\ No newline at end of file
script(type='text/javascript').
var alertsData = [];
\ No newline at end of file
views/modals/editor-video.pug
0 → 100644
View file @
4625a302
.modal#modal-editor-video
.modal-background
.modal-container
.modal-content
header.is-green Insert Video Player
section
label.label Enter the link to the video to be embedded:
p.control.is-fullwidth
input.input(type='text', placeholder='https://www.youtube.com/watch?v=xxxxxxxxxxx', v-model='link')
span.help.is-red.is-hidden This URL is invalid or not supported!
.note The following are supported:
ul
li
i.icon-youtube-play
span Youtube
li
i.icon-vimeo
span Vimeo
li
i.icon-film
span Dailymotion
li
i.icon-video
span Any standard MP4 file
footer
a.button.is-grey.is-outlined(v-on:click="cancel") Discard
a.button.is-green(v-on:click="insertVideo") Insert Video
\ No newline at end of file
views/pages/create.pug
View file @
4625a302
...
...
@@ -22,4 +22,6 @@ block content
include ../modals/create-discard.pug
include ../modals/editor-link.pug
include ../modals/editor-image.pug
include ../modals/editor-file.pug
include ../modals/editor-video.pug
include ../modals/editor-codeblock.pug
\ No newline at end of file
views/pages/edit.pug
View file @
4625a302
...
...
@@ -23,4 +23,5 @@ block content
include ../modals/editor-link.pug
include ../modals/editor-image.pug
include ../modals/editor-file.pug
include ../modals/editor-video.pug
include ../modals/editor-codeblock.pug
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment