Compare commits

..

2 Commits

Author SHA1 Message Date
75332c148d Added protection/permissions. 2016-02-17 12:24:58 +01:00
b54fd85172 Added files module, with for now, a focus on upload files facility.
Contribution from Fabian Murer, as part of an ETH student project.
Supervised, refactorized and merged by Jocelyn Fiat.

Signed-off-by: Fabian Murer <fmurer@student.ethz.ch>
Signed-off-by: Jocelyn Fiat <git@djoce.net>
2016-02-17 12:03:24 +01:00
22 changed files with 7660 additions and 3457 deletions

View File

@@ -1,3 +1,4 @@
@echo off
setlocal setlocal
set ROC_CMD=call %~dp0..\..\tools\roc.bat set ROC_CMD=call %~dp0..\..\tools\roc.bat
set ROC_CMS_DIR=%~dp0 set ROC_CMS_DIR=%~dp0

View File

@@ -1,38 +1,44 @@
.uploaded-files { .uploaded-files table {
width: 100%; width: 100%;
border-collapse: collapse; border-collapse: collapse;
border: 1px solid black; border: 1px solid black;
} }
.uploaded-files th { .uploaded-files table th {
padding-left: 5px; padding: 3px 0 3px 5px;
padding-top: 3px;
padding-bottom: 3px;
} }
.uploaded-files td { .uploaded-files table td {
padding-left: 5px; padding: 3px 0 3px 5px;
padding-top: 3px;
padding-bottom: 3px;
} }
.uploaded-files a.button { .uploaded-files a.button {
color: black; color: black;
text-decoration: none; text-decoration: none;
border: solid 1px #999; border: solid 1px #999;
background-color: #ddd; background-color: #ddd;
padding: 2px 4px 2px 4px;
} }
.uploaded-files a.button:hover { .uploaded-files a.button:hover {
color: black; color: black;
text-decoration: none; border: solid 1px #06f;
background-color: #cff;
} }
.upload-files a.upload-button { .upload-files .center {
text-align: center;
padding: 10px;
}
.upload-files a.button {
margin: auto; margin: auto;
width: 100px; width: 100px;
color: black; color: black;
text-decoration: none; text-decoration: none;
border: solid 1px #999;
background-color: #ddd;
padding: 2px 4px 2px 4px;
} }
.upload-files a.upload-button:hover { .upload-files a.button:hover {
color: black; color: black;
text-decoration: none; border: solid 1px #06f;
background-color: #cff;
} }
/******************* Drop Zone *******************/ /******************* Drop Zone *******************/
@@ -44,18 +50,3 @@
padding-top: 15px; padding-top: 15px;
padding-bottom: 15px; padding-bottom: 15px;
} }
.dropzone .dz-message {
cursor: pointer;
}
.dropzone .dz-preview, .dropzone .dz-file-preview, .dropzone .dz-processing, .dropzone .dz-success,
.dropzone .dz-image-preview, .dropzone .dz-complete {
padding: 10px;
margin: 10px;
width: auto;
display: inline-block;
}
.dropzone .dz-preview {
border: 1px solid black;
border-radius: 5px;
background: #e6e6e6;
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,78 @@
/*
* The MIT License
* Copyright (c) 2012 Matias Meno <m@tias.me>
*/
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
.dropzone, .dropzone * {
box-sizing: border-box;
}
.dropzone {
position: relative;
.dz-preview {
position: relative;
display: inline-block;
width: 120px;
margin: 0.5em;
.dz-progress {
display: block;
height: 15px;
border: 1px solid #aaa;
.dz-upload {
display: block;
height: 100%;
width: 0;
background: green;
}
}
.dz-error-message {
color: red;
display: none;
}
&.dz-error {
.dz-error-message, .dz-error-mark {
display: block;
}
}
&.dz-success {
.dz-success-mark {
display: block;
}
}
.dz-error-mark, .dz-success-mark {
position: absolute;
display: none;
left: 30px;
top: 30px;
width: 54px;
height: 58px;
left: 50%;
margin-left: -(54px/2);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,413 @@
/*
* The MIT License
* Copyright (c) 2012 Matias Meno <m@tias.me>
*/
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
@mixin keyframes($name) {
@-webkit-keyframes #{$name} {
@content;
}
@-moz-keyframes #{$name} {
@content;
}
@keyframes #{$name} {
@content;
}
}
@mixin prefix($map, $vendors: webkit moz ms o) {
@each $prop, $value in $map {
@if $vendors {
@each $vendor in $vendors {
#{"-" + $vendor + "-" + $prop}: #{$value};
}
}
// Dump regular property anyway
#{$prop}: #{$value};
}
}
@include keyframes(passing-through) {
0% {
opacity: 0;
@include prefix((transform: translateY(40px)));
}
30%, 70% {
opacity: 1;
@include prefix((transform: translateY(0px)));
}
100% {
opacity: 0;
@include prefix((transform: translateY(-40px)));
}
}
@include keyframes(slide-in) {
0% {
opacity: 0;
@include prefix((transform: translateY(40px)));
}
30% {
opacity: 1;
@include prefix((transform: translateY(0px)));
}
}
@include keyframes(pulse) {
0% { @include prefix((transform: scale(1))); }
10% { @include prefix((transform: scale(1.1))); }
20% { @include prefix((transform: scale(1))); }
}
.dropzone, .dropzone * {
box-sizing: border-box;
}
.dropzone {
$image-size: 120px;
$image-border-radius: 20px;
&.dz-clickable {
cursor: pointer;
* {
cursor: default;
}
.dz-message {
&, * {
cursor: pointer;
}
}
}
min-height: 150px;
border: 2px solid rgba(0, 0, 0, 0.3);
background: white;
padding: 20px 20px;
&.dz-started {
.dz-message {
display: none;
}
}
&.dz-drag-hover {
border-style: solid;
.dz-message {
opacity: 0.5;
}
}
.dz-message {
text-align: center;
margin: 2em 0;
}
.dz-preview {
position: relative;
display: inline-block;
vertical-align: top;
margin: 16px;
min-height: 100px;
&:hover {
// Making sure that always the hovered preview element is on top
z-index: 1000;
.dz-details {
opacity: 1;
}
}
&.dz-file-preview {
.dz-image {
border-radius: $image-border-radius;
background: #999;
background: linear-gradient(to bottom, #eee, #ddd);
}
.dz-details {
opacity: 1;
}
}
&.dz-image-preview {
background: white;
.dz-details {
@include prefix((transition: opacity 0.2s linear));
}
}
.dz-remove {
font-size: 14px;
text-align: center;
display: block;
cursor: pointer;
border: none;
&:hover {
text-decoration: underline;
}
}
&:hover .dz-details {
opacity: 1;
}
.dz-details {
$background-color: #444;
z-index: 20;
position: absolute;
top: 0;
left: 0;
opacity: 0;
font-size: 13px;
min-width: 100%;
max-width: 100%;
padding: 2em 1em;
text-align: center;
color: rgba(0, 0, 0, 0.9);
$width: 120px;
line-height: 150%;
.dz-size {
margin-bottom: 1em;
font-size: 16px;
}
.dz-filename {
white-space: nowrap;
&:hover {
span {
border: 1px solid rgba(200, 200, 200, 0.8);
background-color: rgba(255, 255, 255, 0.8);
}
}
&:not(:hover) {
span {
border: 1px solid transparent;
}
overflow: hidden;
text-overflow: ellipsis;
}
}
.dz-filename, .dz-size {
span {
background-color: rgba(255, 255, 255, 0.4);
padding: 0 0.4em;
border-radius: 3px;
}
}
}
&:hover {
.dz-image {
// opacity: 0.8;
img {
@include prefix((transform: scale(1.05, 1.05))); // Getting rid of that white bleed-in
@include prefix((filter: blur(8px)), webkit); // Getting rid of that white bleed-in
}
}
}
.dz-image {
border-radius: $image-border-radius;
overflow: hidden;
width: $image-size;
height: $image-size;
position: relative;
display: block;
z-index: 10;
img {
display: block;
}
}
&.dz-success {
.dz-success-mark {
@include prefix((animation: passing-through 3s cubic-bezier(0.770, 0.000, 0.175, 1.000)));
}
}
&.dz-error {
.dz-error-mark {
opacity: 1;
@include prefix((animation: slide-in 3s cubic-bezier(0.770, 0.000, 0.175, 1.000)));
}
}
.dz-success-mark, .dz-error-mark {
$image-height: 54px;
$image-width: 54px;
pointer-events: none;
opacity: 0;
z-index: 500;
position: absolute;
display: block;
top: 50%;
left: 50%;
margin-left: -($image-width/2);
margin-top: -($image-height/2);
svg {
display: block;
width: $image-width;
height: $image-height;
}
}
&.dz-processing .dz-progress {
opacity: 1;
@include prefix((transition: all 0.2s linear));
}
&.dz-complete .dz-progress {
opacity: 0;
@include prefix((transition: opacity 0.4s ease-in));
}
&:not(.dz-processing) {
.dz-progress {
@include prefix((animation: pulse 6s ease infinite));
}
}
.dz-progress {
opacity: 1;
z-index: 1000;
pointer-events: none;
position: absolute;
height: 16px;
left: 50%;
top: 50%;
margin-top: -8px;
width: 80px;
margin-left: -40px;
// border: 2px solid #333;
background: rgba(255, 255, 255, 0.9);
// Fix for chrome bug: https://code.google.com/p/chromium/issues/detail?id=157218
-webkit-transform: scale(1);
border-radius: 8px;
overflow: hidden;
.dz-upload {
background: #333;
background: linear-gradient(to bottom, #666, #444);
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 0;
@include prefix((transition: width 300ms ease-in-out));
}
}
&.dz-error {
.dz-error-message {
display: block;
}
&:hover .dz-error-message {
opacity: 1;
pointer-events: auto;
}
}
.dz-error-message {
$width: $image-size + 20px;
$color: rgb(190, 38, 38);
pointer-events: none;
z-index: 1000;
position: absolute;
display: block;
display: none;
opacity: 0;
@include prefix((transition: opacity 0.3s ease));
border-radius: 8px;
font-size: 13px;
top: $image-size + 10px;
left: -10px;
width: $width;
background: $color;
background: linear-gradient(to bottom, $color, darken($color, 5%));
padding: 0.5em 1.2em;
color: white;
// The triangle pointing up
&:after {
content: '';
position: absolute;
top: -6px;
left: $width / 2 - 6px;
width: 0;
height: 0;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-bottom: 6px solid $color;
}
}
}
}

View File

@@ -1,18 +1,16 @@
.uploaded-files { .uploaded-files {
width: 100%; table {
border-collapse: collapse; width: 100%;
border: 1px solid black; border-collapse: collapse;
border: 1px solid black;
th { th {
padding-left: 5px; padding: 3px 0 3px 5px;
padding-top: 3px; }
padding-bottom: 3px;
}
td { td {
padding-left: 5px; padding: 3px 0 3px 5px;
padding-top: 3px; }
padding-bottom: 3px;
} }
a.button{ a.button{
@@ -20,23 +18,33 @@
text-decoration: none; text-decoration: none;
border: solid 1px #999; border: solid 1px #999;
background-color: #ddd; background-color: #ddd;
padding: 2px 4px 2px 4px;
&:hover { &:hover {
color: black; color: black;
text-decoration: none; border: solid 1px #06f;
background-color: #cff;
} }
} }
} }
.upload-files { .upload-files {
a.upload-button{ .center {
text-align: center;
padding: 10px;
}
a.button{
margin: auto; margin: auto;
width: 100px; width: 100px;
color: black; color: black;
text-decoration: none; text-decoration: none;
border: solid 1px #999;
background-color: #ddd;
padding: 2px 4px 2px 4px;
&:hover { &:hover {
color: black; color: black;
text-decoration: none; border: solid 1px #06f;
background-color: #cff;
} }
} }
} }
@@ -51,23 +59,5 @@
text-align: center; text-align: center;
padding-top: 15px; padding-top: 15px;
padding-bottom: 15px; padding-bottom: 15px;
.dz-message {
cursor: pointer;
}
.dz-preview, .dz-file-preview, .dz-processing, .dz-success,
.dz-image-preview, .dz-complete {
padding: 10px;
margin: 10px;
width: auto;
display: inline-block;
}
.dz-preview {
border: 1px solid black;
border-radius: 5px;
background: #e6e6e6;
}
} }

View File

@@ -103,7 +103,7 @@ feature -- Storage
end end
end end
save_uploaded_file (f: CMS_UPLOADED_FILE) save_uploaded_file (uf: CMS_UPLOADED_FILE)
local local
p: PATH p: PATH
ut: FILE_UTILITIES ut: FILE_UTILITIES
@@ -113,9 +113,9 @@ feature -- Storage
finished: BOOLEAN finished: BOOLEAN
do do
reset_error reset_error
create original_name.make_from_string (f.filename) create original_name.make_from_string (uf.filename)
p := f.location p := uf.location
if not p.is_absolute then if not p.is_absolute then
p := uploads_directory.extended_path (p) p := uploads_directory.extended_path (p)
end end
@@ -128,8 +128,8 @@ feature -- Storage
finished finished
loop loop
if ut.file_path_exists (p) then if ut.file_path_exists (p) then
f.set_new_location_with_number (n) uf.set_new_location_with_number (n)
p := f.location p := uf.location
if p.is_absolute then if p.is_absolute then
else else
p := uploads_directory.extended_path (p) p := uploads_directory.extended_path (p)
@@ -139,13 +139,15 @@ feature -- Storage
finished := True finished := True
end end
end end
stored := f.move_to (p) stored := uf.move_to (p)
else else
-- move file to path -- move file to path
stored := f.move_to (p) stored := uf.move_to (p)
end end
if not stored then if stored then
save_metadata_from_uploaded_file (uf, cms_api.user)
else
error_handler.add_custom_error (-1, "uploaded file storage failed", "Issue occurred when saving uploaded file!") error_handler.add_custom_error (-1, "uploaded file storage failed", "Issue occurred when saving uploaded file!")
end end
end end
@@ -156,7 +158,7 @@ feature -- Storage
h_date: HTTP_DATE h_date: HTTP_DATE
retried: BOOLEAN retried: BOOLEAN
do do
if not retried then if retried then
-- FIXME: Report error? -- FIXME: Report error?
if f /= Void and then not f.is_closed then if f /= Void and then not f.is_closed then
f.close f.close
@@ -172,7 +174,7 @@ feature -- Storage
end end
-- insert username -- insert username
if u /= Void then if u /= Void then
f.put_integer_64 (u.id) f.put_string (u.id.out)
f.put_new_line f.put_new_line
-- f.put_string (utf.utf_32_string_to_utf_8_string_8 (u.name)) -- f.put_string (utf.utf_32_string_to_utf_8_string_8 (u.name))
-- f.put_new_line -- f.put_new_line
@@ -182,7 +184,7 @@ feature -- Storage
end end
-- insert uploaded_time -- insert uploaded_time
create h_date.make_now_utc create h_date.make_now_utc
f.put_integer_64 (h_date.timestamp) f.put_string (h_date.timestamp.out)
f.put_new_line f.put_new_line
-- insert size of file -- insert size of file

View File

@@ -43,10 +43,15 @@ feature -- Access
-- List of permission ids, used by this module, and declared. -- List of permission ids, used by this module, and declared.
do do
Result := Precursor Result := Precursor
Result.force ("admin files") Result.force (admin_files_permission)
Result.force ("upload files") Result.force (upload_files_permission)
Result.force (browse_files_permission)
end end
admin_files_permission: STRING = "admin files"
upload_files_permission: STRING = "upload files"
browse_files_permission: STRING = "browse files"
feature {CMS_API} -- Module Initialization feature {CMS_API} -- Module Initialization
initialize (api: CMS_API) initialize (api: CMS_API)
@@ -92,7 +97,7 @@ feature -- Access: router
do do
map_uri_template_agent (a_router, "/" + uploads_location, agent execute_upload (?, ?, a_api), Void) -- Accepts any method GET, HEAD, POST, PUT, DELETE, ... map_uri_template_agent (a_router, "/" + uploads_location, agent execute_upload (?, ?, a_api), Void) -- Accepts any method GET, HEAD, POST, PUT, DELETE, ...
map_uri_template_agent (a_router, "/" + uploads_location + "{filename}", agent display_uploaded_file_info (?, ?, a_api), a_router.methods_get) map_uri_template_agent (a_router, "/" + uploads_location + "{filename}", agent display_uploaded_file_info (?, ?, a_api), a_router.methods_get)
map_uri_template_agent (a_router, "/" + uploads_location + "remove/{filename}", agent remove (?, ?, a_api), a_router.methods_get) map_uri_template_agent (a_router, "/" + uploads_location + "remove/{filename}", agent remove_file (?, ?, a_api), a_router.methods_get)
end end
uploads_location: STRING = "upload/" uploads_location: STRING = "upload/"
@@ -109,7 +114,7 @@ feature -- Hooks
link: CMS_LOCAL_LINK link: CMS_LOCAL_LINK
do do
-- login in demo did somehow not work -- login in demo did somehow not work
if a_response.has_permission ("upload files") then if a_response.has_permission (upload_files_permission) then
create link.make ("Upload files", uploads_location) create link.make ("Upload files", uploads_location)
a_menu_system.navigation_menu.extend (link) a_menu_system.navigation_menu.extend (link)
end end
@@ -133,13 +138,17 @@ feature -- Handler
fn: READABLE_STRING_32 fn: READABLE_STRING_32
do do
check req.is_get_request_method end check req.is_get_request_method end
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) if not api.has_permission (browse_files_permission) then
create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api)
r.add_error_message ("You are not allowed to browse CMS files!")
elseif attached {WSF_STRING} req.path_parameter ("filename") as p_filename then
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
-- add style -- add style
r.add_style (r.url ("/module/" + name + "/files/css/files.css", Void), Void) r.add_style (r.url ("/module/" + name + "/files/css/files.css", Void), Void)
create body.make_empty
create body.make_empty
if attached {WSF_STRING} req.path_parameter ("filename") as p_filename then
fn := p_filename.value fn := p_filename.value
r.set_page_title ({STRING_32} "File %"" + fn + {STRING_32} "%"") r.set_page_title ({STRING_32} "File %"" + fn + {STRING_32} "%"")
body.append ("<div class=%"uploaded-files%">%N") -- To ease css customization. body.append ("<div class=%"uploaded-files%">%N") -- To ease css customization.
@@ -207,9 +216,13 @@ feature -- Handler
body.append ("</div>%N") -- Overview body.append ("</div>%N") -- Overview
end end
body.append ("</div>%N") body.append ("</div>%N")
r.add_to_primary_tabs (create {CMS_LOCAL_LINK}.make ("Uploaded files", uploads_location))
r.set_main_content (body)
else
create {BAD_REQUEST_ERROR_CMS_RESPONSE} r.make (req, res, api)
r.set_main_content ("Missing 'filename' field value!")
end end
r.add_to_primary_tabs (create {CMS_LOCAL_LINK}.make ("Uploaded files", uploads_location))
r.set_main_content (body)
r.execute r.execute
end end
@@ -229,8 +242,9 @@ feature -- Handler
-- add JS for dropzone -- add JS for dropzone
r.add_javascript_url (r.url ("/module/" + name + "/files/js/dropzone.js", void)) r.add_javascript_url (r.url ("/module/" + name + "/files/js/dropzone.js", void))
r.add_style (r.url ("/module/" + name + "/files/js/dropzone.css", void), void)
if r.has_permission ("upload files") then if api.has_permission (upload_files_permission) then
-- create body -- create body
body.append ("<p>Please choose some file(s) to upload.</p>") body.append ("<p>Please choose some file(s) to upload.</p>")
@@ -238,7 +252,7 @@ feature -- Handler
body.append ("<div class=%"upload-files%">") body.append ("<div class=%"upload-files%">")
body.append ("<form action=%"" + r.url (uploads_location, Void) + "%" class=%"dropzone%">") body.append ("<form action=%"" + r.url (uploads_location, Void) + "%" class=%"dropzone%">")
body.append ("</form>%N") body.append ("</form>%N")
body.append ("<a class=%"button%" href=%""+ r.url (uploads_location, Void) +"%">Upload Files</a>") body.append ("<div class=%"center%"><a class=%"button%" href=%""+ r.url (uploads_location, Void) +"%">Upload Files</a></div>")
body.append ("</div>") body.append ("</div>")
if req.is_post_request_method then if req.is_post_request_method then
process_uploaded_files (req, api, body) process_uploaded_files (req, api, body)
@@ -248,8 +262,11 @@ feature -- Handler
end end
-- Build the response. -- Build the response.
if r.has_permission (browse_files_permission) then
append_uploaded_file_album_to (req, api, body) append_uploaded_file_album_to (req, api, body)
else
r.add_warning_message ("You are not allowed to browse files!")
end
r.set_main_content (body) r.set_main_content (body)
else else
@@ -259,7 +276,9 @@ feature -- Handler
end end
process_uploaded_files (req: WSF_REQUEST; api: CMS_API; a_output: STRING) process_uploaded_files (req: WSF_REQUEST; api: CMS_API; a_output: STRING)
-- show all newly uploaded files -- Process http request uploaded files.
require
has_permission: api.has_permission (upload_files_permission)
local local
l_uploaded_file: CMS_UPLOADED_FILE l_uploaded_file: CMS_UPLOADED_FILE
uf: WSF_UPLOADED_FILE uf: WSF_UPLOADED_FILE
@@ -277,14 +296,12 @@ feature -- Handler
a_output.append ("<li>") a_output.append ("<li>")
a_output.append (api.html_encoded (l_uploaded_file.filename)) a_output.append (api.html_encoded (l_uploaded_file.filename))
-- store the just uploaded file
l_files_api.save_uploaded_file (l_uploaded_file)
-- create medadata file -- create medadata file
l_uploaded_file.set_size (uf.size) l_uploaded_file.set_size (uf.size)
l_uploaded_file.set_type (uf.content_type) l_uploaded_file.set_type (uf.content_type)
l_files_api.save_metadata_from_uploaded_file (l_uploaded_file, api.current_user (req)) -- store the just uploaded file
l_files_api.save_uploaded_file (l_uploaded_file)
if l_files_api.has_error then if l_files_api.has_error then
a_output.append (" <span class=%"error%">: upload failed!</span>") a_output.append (" <span class=%"error%">: upload failed!</span>")
@@ -303,14 +320,14 @@ feature -- Handler
p: PATH p: PATH
rel: PATH rel: PATH
md: detachable CMS_FILE_METADATA md: detachable CMS_FILE_METADATA
size: INTEGER
do do
if attached files_api as l_files_api then if attached files_api as l_files_api then
rel := l_files_api.uploads_relative_path rel := l_files_api.uploads_relative_path
p := l_files_api.uploads_directory p := l_files_api.uploads_directory
a_output.append ("<div class=%"uploaded-files%">%N")
a_output.append ("<strong>Uploaded files:</strong>%N") a_output.append ("<strong>Uploaded files:</strong>%N")
a_output.append ("<table class=%"uploaded-files%">%N") a_output.append ("<table>%N")
a_output.append ("<tr><th>Filename</th><th>Uploading Time</th><th>User</th><th>Size</th><th></th><th></th></tr>%N") a_output.append ("<tr><th>Filename</th><th>Uploading Time</th><th>User</th><th>Size</th><th></th><th></th></tr>%N")
create d.make_with_path (p) create d.make_with_path (p)
@@ -361,18 +378,7 @@ feature -- Handler
-- add size -- add size
a_output.append ("<td class=%"size%">") a_output.append ("<td class=%"size%">")
if md.size > 0 then if md.size > 0 then
size := md.size a_output.append (file_size_human_string (md.size))
if size >= 1000000 then
size := size // 1000000
a_output.append (size.out + " MB")
else
if size >= 1000 then
size := size // 1000
a_output.append (size.out + " kB")
else
a_output.append (size.out + " bytes")
end
end
else else
a_output.append ("NA") a_output.append ("NA")
end end
@@ -381,12 +387,12 @@ feature -- Handler
-- add download link -- add download link
a_output.append ("<td>") a_output.append ("<td>")
a_output.append ("<button><a class=%"download-button%" href=%"" + req.script_url ("/" + l_files_api.file_link (f).location) + "%" download>Download</a></button>%N") a_output.append ("<a class=%"button%" href=%"" + req.script_url ("/" + l_files_api.file_link (f).location) + "%" download>Download</a>%N")
a_output.append ("</td>%N") a_output.append ("</td>%N")
-- add remove button -- add remove button
a_output.append ("<td>") a_output.append ("<td>")
a_output.append ("<button><a class=%"download-button%" href=%"" + req.script_url ("/" + uploads_location + "remove/" + f.filename) + "%">Remove</a></button>%N") a_output.append ("<a class=%"button%" href=%"" + req.script_url ("/" + uploads_location + "remove/" + f.filename) + "%">Remove</a>%N")
a_output.append ("</td>%N") a_output.append ("</td>%N")
a_output.append ("</tr>%N") a_output.append ("</tr>%N")
@@ -414,18 +420,21 @@ feature -- Handler
end end
end end
a_output.append ("</table>%N") a_output.append ("</table>%N")
a_output.append ("</div>%N")
end end
end end
remove (req: WSF_REQUEST; res: WSF_RESPONSE; api: CMS_API) remove_file (req: WSF_REQUEST; res: WSF_RESPONSE; api: CMS_API)
local local
body: STRING body: STRING
r: CMS_RESPONSE r: CMS_RESPONSE
err: BOOLEAN err: BOOLEAN
do do
if attached files_api as l_files_api then if attached files_api as l_files_api then
if attached {WSF_STRING} req.path_parameter ("filename") as p_filename then if not api.has_permission (admin_files_permission) then
create {FORBIDDEN_ERROR_CMS_RESPONSE} r.make (req, res, api)
r.add_error_message ("You are not allowed to remove file!")
elseif attached {WSF_STRING} req.path_parameter ("filename") as p_filename then
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
l_files_api.delete_file (p_filename.value) l_files_api.delete_file (p_filename.value)

View File

@@ -1,38 +1,44 @@
.uploaded-files { .uploaded-files table {
width: 100%; width: 100%;
border-collapse: collapse; border-collapse: collapse;
border: 1px solid black; border: 1px solid black;
} }
.uploaded-files th { .uploaded-files table th {
padding-left: 5px; padding: 3px 0 3px 5px;
padding-top: 3px;
padding-bottom: 3px;
} }
.uploaded-files td { .uploaded-files table td {
padding-left: 5px; padding: 3px 0 3px 5px;
padding-top: 3px;
padding-bottom: 3px;
} }
.uploaded-files a.button { .uploaded-files a.button {
color: black; color: black;
text-decoration: none; text-decoration: none;
border: solid 1px #999; border: solid 1px #999;
background-color: #ddd; background-color: #ddd;
padding: 2px 4px 2px 4px;
} }
.uploaded-files a.button:hover { .uploaded-files a.button:hover {
color: black; color: black;
text-decoration: none; border: solid 1px #06f;
background-color: #cff;
} }
.upload-files a.upload-button { .upload-files .center {
text-align: center;
padding: 10px;
}
.upload-files a.button {
margin: auto; margin: auto;
width: 100px; width: 100px;
color: black; color: black;
text-decoration: none; text-decoration: none;
border: solid 1px #999;
background-color: #ddd;
padding: 2px 4px 2px 4px;
} }
.upload-files a.upload-button:hover { .upload-files a.button:hover {
color: black; color: black;
text-decoration: none; border: solid 1px #06f;
background-color: #cff;
} }
/******************* Drop Zone *******************/ /******************* Drop Zone *******************/
@@ -44,18 +50,3 @@
padding-top: 15px; padding-top: 15px;
padding-bottom: 15px; padding-bottom: 15px;
} }
.dropzone .dz-message {
cursor: pointer;
}
.dropzone .dz-preview, .dropzone .dz-file-preview, .dropzone .dz-processing, .dropzone .dz-success,
.dropzone .dz-image-preview, .dropzone .dz-complete {
padding: 10px;
margin: 10px;
width: auto;
display: inline-block;
}
.dropzone .dz-preview {
border: 1px solid black;
border-radius: 5px;
background: #e6e6e6;
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,78 @@
/*
* The MIT License
* Copyright (c) 2012 Matias Meno <m@tias.me>
*/
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
.dropzone, .dropzone * {
box-sizing: border-box;
}
.dropzone {
position: relative;
.dz-preview {
position: relative;
display: inline-block;
width: 120px;
margin: 0.5em;
.dz-progress {
display: block;
height: 15px;
border: 1px solid #aaa;
.dz-upload {
display: block;
height: 100%;
width: 0;
background: green;
}
}
.dz-error-message {
color: red;
display: none;
}
&.dz-error {
.dz-error-message, .dz-error-mark {
display: block;
}
}
&.dz-success {
.dz-success-mark {
display: block;
}
}
.dz-error-mark, .dz-success-mark {
position: absolute;
display: none;
left: 30px;
top: 30px;
width: 54px;
height: 58px;
left: 50%;
margin-left: -(54px/2);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,413 @@
/*
* The MIT License
* Copyright (c) 2012 Matias Meno <m@tias.me>
*/
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
@mixin keyframes($name) {
@-webkit-keyframes #{$name} {
@content;
}
@-moz-keyframes #{$name} {
@content;
}
@keyframes #{$name} {
@content;
}
}
@mixin prefix($map, $vendors: webkit moz ms o) {
@each $prop, $value in $map {
@if $vendors {
@each $vendor in $vendors {
#{"-" + $vendor + "-" + $prop}: #{$value};
}
}
// Dump regular property anyway
#{$prop}: #{$value};
}
}
@include keyframes(passing-through) {
0% {
opacity: 0;
@include prefix((transform: translateY(40px)));
}
30%, 70% {
opacity: 1;
@include prefix((transform: translateY(0px)));
}
100% {
opacity: 0;
@include prefix((transform: translateY(-40px)));
}
}
@include keyframes(slide-in) {
0% {
opacity: 0;
@include prefix((transform: translateY(40px)));
}
30% {
opacity: 1;
@include prefix((transform: translateY(0px)));
}
}
@include keyframes(pulse) {
0% { @include prefix((transform: scale(1))); }
10% { @include prefix((transform: scale(1.1))); }
20% { @include prefix((transform: scale(1))); }
}
.dropzone, .dropzone * {
box-sizing: border-box;
}
.dropzone {
$image-size: 120px;
$image-border-radius: 20px;
&.dz-clickable {
cursor: pointer;
* {
cursor: default;
}
.dz-message {
&, * {
cursor: pointer;
}
}
}
min-height: 150px;
border: 2px solid rgba(0, 0, 0, 0.3);
background: white;
padding: 20px 20px;
&.dz-started {
.dz-message {
display: none;
}
}
&.dz-drag-hover {
border-style: solid;
.dz-message {
opacity: 0.5;
}
}
.dz-message {
text-align: center;
margin: 2em 0;
}
.dz-preview {
position: relative;
display: inline-block;
vertical-align: top;
margin: 16px;
min-height: 100px;
&:hover {
// Making sure that always the hovered preview element is on top
z-index: 1000;
.dz-details {
opacity: 1;
}
}
&.dz-file-preview {
.dz-image {
border-radius: $image-border-radius;
background: #999;
background: linear-gradient(to bottom, #eee, #ddd);
}
.dz-details {
opacity: 1;
}
}
&.dz-image-preview {
background: white;
.dz-details {
@include prefix((transition: opacity 0.2s linear));
}
}
.dz-remove {
font-size: 14px;
text-align: center;
display: block;
cursor: pointer;
border: none;
&:hover {
text-decoration: underline;
}
}
&:hover .dz-details {
opacity: 1;
}
.dz-details {
$background-color: #444;
z-index: 20;
position: absolute;
top: 0;
left: 0;
opacity: 0;
font-size: 13px;
min-width: 100%;
max-width: 100%;
padding: 2em 1em;
text-align: center;
color: rgba(0, 0, 0, 0.9);
$width: 120px;
line-height: 150%;
.dz-size {
margin-bottom: 1em;
font-size: 16px;
}
.dz-filename {
white-space: nowrap;
&:hover {
span {
border: 1px solid rgba(200, 200, 200, 0.8);
background-color: rgba(255, 255, 255, 0.8);
}
}
&:not(:hover) {
span {
border: 1px solid transparent;
}
overflow: hidden;
text-overflow: ellipsis;
}
}
.dz-filename, .dz-size {
span {
background-color: rgba(255, 255, 255, 0.4);
padding: 0 0.4em;
border-radius: 3px;
}
}
}
&:hover {
.dz-image {
// opacity: 0.8;
img {
@include prefix((transform: scale(1.05, 1.05))); // Getting rid of that white bleed-in
@include prefix((filter: blur(8px)), webkit); // Getting rid of that white bleed-in
}
}
}
.dz-image {
border-radius: $image-border-radius;
overflow: hidden;
width: $image-size;
height: $image-size;
position: relative;
display: block;
z-index: 10;
img {
display: block;
}
}
&.dz-success {
.dz-success-mark {
@include prefix((animation: passing-through 3s cubic-bezier(0.770, 0.000, 0.175, 1.000)));
}
}
&.dz-error {
.dz-error-mark {
opacity: 1;
@include prefix((animation: slide-in 3s cubic-bezier(0.770, 0.000, 0.175, 1.000)));
}
}
.dz-success-mark, .dz-error-mark {
$image-height: 54px;
$image-width: 54px;
pointer-events: none;
opacity: 0;
z-index: 500;
position: absolute;
display: block;
top: 50%;
left: 50%;
margin-left: -($image-width/2);
margin-top: -($image-height/2);
svg {
display: block;
width: $image-width;
height: $image-height;
}
}
&.dz-processing .dz-progress {
opacity: 1;
@include prefix((transition: all 0.2s linear));
}
&.dz-complete .dz-progress {
opacity: 0;
@include prefix((transition: opacity 0.4s ease-in));
}
&:not(.dz-processing) {
.dz-progress {
@include prefix((animation: pulse 6s ease infinite));
}
}
.dz-progress {
opacity: 1;
z-index: 1000;
pointer-events: none;
position: absolute;
height: 16px;
left: 50%;
top: 50%;
margin-top: -8px;
width: 80px;
margin-left: -40px;
// border: 2px solid #333;
background: rgba(255, 255, 255, 0.9);
// Fix for chrome bug: https://code.google.com/p/chromium/issues/detail?id=157218
-webkit-transform: scale(1);
border-radius: 8px;
overflow: hidden;
.dz-upload {
background: #333;
background: linear-gradient(to bottom, #666, #444);
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 0;
@include prefix((transition: width 300ms ease-in-out));
}
}
&.dz-error {
.dz-error-message {
display: block;
}
&:hover .dz-error-message {
opacity: 1;
pointer-events: auto;
}
}
.dz-error-message {
$width: $image-size + 20px;
$color: rgb(190, 38, 38);
pointer-events: none;
z-index: 1000;
position: absolute;
display: block;
display: none;
opacity: 0;
@include prefix((transition: opacity 0.3s ease));
border-radius: 8px;
font-size: 13px;
top: $image-size + 10px;
left: -10px;
width: $width;
background: $color;
background: linear-gradient(to bottom, $color, darken($color, 5%));
padding: 0.5em 1.2em;
color: white;
// The triangle pointing up
&:after {
content: '';
position: absolute;
top: -6px;
left: $width / 2 - 6px;
width: 0;
height: 0;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-bottom: 6px solid $color;
}
}
}
}

View File

@@ -1,18 +1,16 @@
.uploaded-files { .uploaded-files {
width: 100%; table {
border-collapse: collapse; width: 100%;
border: 1px solid black; border-collapse: collapse;
border: 1px solid black;
th { th {
padding-left: 5px; padding: 3px 0 3px 5px;
padding-top: 3px; }
padding-bottom: 3px;
}
td { td {
padding-left: 5px; padding: 3px 0 3px 5px;
padding-top: 3px; }
padding-bottom: 3px;
} }
a.button{ a.button{
@@ -20,23 +18,33 @@
text-decoration: none; text-decoration: none;
border: solid 1px #999; border: solid 1px #999;
background-color: #ddd; background-color: #ddd;
padding: 2px 4px 2px 4px;
&:hover { &:hover {
color: black; color: black;
text-decoration: none; border: solid 1px #06f;
background-color: #cff;
} }
} }
} }
.upload-files { .upload-files {
a.upload-button{ .center {
text-align: center;
padding: 10px;
}
a.button{
margin: auto; margin: auto;
width: 100px; width: 100px;
color: black; color: black;
text-decoration: none; text-decoration: none;
border: solid 1px #999;
background-color: #ddd;
padding: 2px 4px 2px 4px;
&:hover { &:hover {
color: black; color: black;
text-decoration: none; border: solid 1px #06f;
background-color: #cff;
} }
} }
} }
@@ -51,23 +59,5 @@
text-align: center; text-align: center;
padding-top: 15px; padding-top: 15px;
padding-bottom: 15px; padding-bottom: 15px;
.dz-message {
cursor: pointer;
}
.dz-preview, .dz-file-preview, .dz-processing, .dz-success,
.dz-image-preview, .dz-complete {
padding: 10px;
margin: 10px;
width: auto;
display: inline-block;
}
.dz-preview {
border: 1px solid black;
border-radius: 5px;
background: #e6e6e6;
}
} }

View File

@@ -9,38 +9,38 @@ deferred class
feature -- Initialisation feature -- Initialisation
load_assets : STRING load_assets: STRING
-- Loads all assest needed to show the editor -- Loads all assest needed to show the editor.
deferred deferred
end end
feature -- Javascript feature -- Javascript
javascript_replace_textarea (a_textarea : WSF_FORM_TEXTAREA): STRING javascript_replace_textarea (a_textarea: WSF_FORM_TEXTAREA): STRING
-- Javascript code that replaces a textarea with the editor. The editor instance should be saved in editor_variable -- Javascript code that replaces a textarea with the editor. The editor instance should be saved in editor_variable.
deferred deferred
end end
javascript_restore_textarea (a_textarea : WSF_FORM_TEXTAREA): STRING javascript_restore_textarea (a_textarea: WSF_FORM_TEXTAREA): STRING
-- Javascript code that restores a textarea -- Javascript code that restores a textarea
deferred deferred
end end
javascript_textarea_to_editor (a_textarea : WSF_FORM_TEXTAREA): STRING javascript_textarea_to_editor (a_textarea: WSF_FORM_TEXTAREA): STRING
-- Javascript code to display the textarea as a WYSIWIG editor as soon as the document is loaded -- Javascript code to display the textarea as a WYSIWIG editor as soon as the document is loaded.
do do
Result := javascript_ready (javascript_replace_textarea (a_textarea)) Result := javascript_ready (javascript_replace_textarea (a_textarea))
end end
javascript_textarea_to_editor_if_selected (a_textarea: WSF_FORM_TEXTAREA; a_select_field : WSF_FORM_SELECT; a_value : STRING) : STRING javascript_textarea_to_editor_if_selected (a_textarea: WSF_FORM_TEXTAREA; a_select_field: WSF_FORM_SELECT; a_value: STRING): STRING
-- Javascript code to display the textarea as a WYSIWIG editor if a_select_field has a_value -- Javascript code to display the textarea as a WYSIWIG editor if a_select_field has a_value,
local local
initial_replace_code, on_select_replace_code: STRING initial_replace_code, on_select_replace_code: STRING
do do
-- Javascript that replaces the textarea if a_value is selected at load time -- Javascript that replaces the textarea if a_value is selected at load time
initial_replace_code := javascript_ready (javascript_if_selected (a_select_field, a_value, javascript_replace_textarea (a_textarea))) initial_replace_code := javascript_ready (javascript_if_selected (a_select_field, a_value, javascript_replace_textarea (a_textarea)))
-- Javascript code that replaces the textarea as soon as value is selected at a_select_field -- Javascript code that replaces the textarea as soon as value is selected at a_select_field
on_select_replace_code := javascript_ready( on_select_replace_code := javascript_ready(
javascript_init_editor_variable (a_textarea) + javascript_init_editor_variable (a_textarea) +
javascript_on_select (a_select_field, a_value, javascript_on_select (a_select_field, a_value,
@@ -55,54 +55,56 @@ feature -- Javascript
Result := initial_replace_code + " " + on_select_replace_code Result := initial_replace_code + " " + on_select_replace_code
end end
javascript_init_editor_variable (a_textarea : WSF_FORM_TEXTAREA) : STRING javascript_init_editor_variable (a_textarea: WSF_FORM_TEXTAREA): STRING
-- Returns the javascript code that initializes a local variable to store the editor instance -- Returns the javascript code that initializes a local variable to store the editor instance.
do do
Result := "var " + editor_variable (a_textarea) + "; " Result := "var " + editor_variable (a_textarea) + "; "
end end
javascript_if_selected (a_select_field : WSF_FORM_SELECT; a_value : STRING; a_code : STRING) : STRING javascript_if_selected (a_select_field: WSF_FORM_SELECT; a_value: STRING; a_code: STRING): STRING
-- Javascript that executes a_code if a_value is selected at a_select_field -- Javascript that executes a_code if a_value is selected at a_select_field.
do do
Result := "if($('#" + field_id (a_select_field) + "').val() == %"" + a_value + "%"){ " + a_code + " }" Result := "if($('#" + field_id (a_select_field) + "').val() == %"" + a_value + "%"){ " + a_code + " }"
end end
javascript_ready (a_code : STRING) : STRING javascript_ready (a_code: STRING): STRING
-- Wraps the given javascript code with a ready statement, such that it's executed when the document has loaded -- Wraps the given javascript code with a ready statement,
-- such that it's executed when the document has loaded.
do do
Result := "$(function() { " + a_code + " });" Result := "$(function() { " + a_code + " });"
end end
javascript_on_select (a_select_field : WSF_FORM_SELECT; a_value : STRING; a_then : STRING; a_else : STRING) : STRING javascript_on_select (a_select_field: WSF_FORM_SELECT; a_value: STRING; a_then: STRING; a_else: STRING): STRING
-- Javascript code that executes a_then if at the given select_field the given string value is selected, otherwise it executes a_else -- Javascript code that executes `a_then' if at the given `a_select_field'
-- the given string `a_value' is selected, otherwise it executes `a_else'.
do do
Result := "$('#" + field_id (a_select_field) + "').change(function(){" + Result := "$('#" + field_id (a_select_field) + "').change(function(){"
javascript_if_selected (a_select_field, a_value, a_then) + + javascript_if_selected (a_select_field, a_value, a_then)
"else{" + + "else{"
a_else + + a_else
"}" + + "}"
"});" + "});"
end end
feature -- Helper feature -- Helper
field_id(a_select_field : WSF_FORM_SELECT) : STRING field_id (a_select_field: WSF_FORM_SELECT): STRING
-- Returns the id of the given field -- Id of the given field.
do do
if attached a_select_field.css_id as a_id then if attached a_select_field.css_id as a_id then
Result := a_id Result := a_id
else else
Result := a_select_field.name + "-select" Result := a_select_field.name + "-select"
end end
end end
editor_variable (a_textarea : WSF_FORM_TEXTAREA) : STRING editor_variable (a_textarea: WSF_FORM_TEXTAREA): STRING
-- Returns the variable name that stores the editor instance of the given textarea -- Returns the variable name that stores the editor instance of the given textarea
do do
Result := "cms_ckeditor_" + a_textarea.name Result := "cms_ckeditor_" + a_textarea.name
end end
note note
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" copyright: "2011-2016, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end end

View File

@@ -12,7 +12,7 @@ inherit
feature -- Initialisation feature -- Initialisation
load_assets : STRING load_assets: STRING
-- <Precursor> -- <Precursor>
do do
Result := "<script src=%"//cdn.ckeditor.com/4.4.7/standard/ckeditor.js%"></script>" Result := "<script src=%"//cdn.ckeditor.com/4.4.7/standard/ckeditor.js%"></script>"
@@ -20,23 +20,25 @@ feature -- Initialisation
feature -- Javascript feature -- Javascript
javascript_replace_textarea (a_textarea : WSF_FORM_TEXTAREA) : STRING javascript_replace_textarea (a_textarea: WSF_FORM_TEXTAREA): STRING
-- <Precursor> -- <Precursor>
do do
-- Replaces the textarea with an editor instance. Save the instance in a variable -- Replaces the textarea with an editor instance.
-- Save the instance in a variable.
Result := "$(%"textarea[name="+ a_textarea.name +"]%").each(function() {" Result := "$(%"textarea[name="+ a_textarea.name +"]%").each(function() {"
Result.append (editor_variable (a_textarea) + " = CKEDITOR.replace(this);") Result.append (editor_variable (a_textarea) + " = CKEDITOR.replace(this);")
Result.append ("});") Result.append ("});")
end end
javascript_restore_textarea (a_textarea : WSF_FORM_TEXTAREA) : STRING javascript_restore_textarea (a_textarea: WSF_FORM_TEXTAREA): STRING
-- <Precursor> -- <Precursor>
do do
-- Replaces the textarea with an editor instance. Save the instance in a variable -- Replaces the textarea with an editor instance.
-- Save the instance in a variable.
Result := "if (" + editor_variable (a_textarea) + " != undefined) " + editor_variable (a_textarea) + ".destroy();" Result := "if (" + editor_variable (a_textarea) + " != undefined) " + editor_variable (a_textarea) + ".destroy();"
end end
note note
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" copyright: "2011-2016, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end end

View File

@@ -282,7 +282,9 @@ feature -- Head customization
local local
s: STRING_8 s: STRING_8
do do
s := "<link rel=%"stylesheet%" href=%""+ a_href + "%" type=%"text/css%"" create s.make_from_string ("<link rel=%"stylesheet%" href=%"")
s.append (a_href)
s.append ("%" type=%"text/css%"")
if a_media /= Void then if a_media /= Void then
s.append (" media=%""+ a_media + "%"") s.append (" media=%""+ a_media + "%"")
end end
@@ -290,11 +292,24 @@ feature -- Head customization
add_additional_head_line (s, False) add_additional_head_line (s, False)
end end
add_style_content (a_style_content: STRING)
-- Add style content `a_style_content' in the head, using <style> tag.
local
s: STRING_8
do
create s.make_from_string ("<style>%N")
s.append (a_style_content)
s.append ("%N</style>")
add_additional_head_line (s, True)
end
add_javascript_url (a_src: STRING) add_javascript_url (a_src: STRING)
local local
s: STRING_8 s: STRING_8
do do
s := "<script type=%"text/javascript%" src=%"" + a_src + "%"></script>" create s.make_from_string ("<script type=%"text/javascript%" src=%"")
s.append (a_src)
s.append ("%"></script>")
add_additional_head_line (s, False) add_additional_head_line (s, False)
end end
@@ -302,7 +317,9 @@ feature -- Head customization
local local
s: STRING_8 s: STRING_8
do do
s := "<script type=%"text/javascript%">%N" + a_script + "%N</script>" create s.make_from_string ("<script type=%"text/javascript%">%N")
s.append (a_script)
s.append ("%N</script>")
add_additional_head_line (s, True) add_additional_head_line (s, True)
end end

View File

@@ -144,12 +144,17 @@ feature -- Element change
title := s title := s
end end
add_additional_head_line (s: READABLE_STRING_8)
do
head_lines.extend (s)
end
add_meta_name_content (a_name: STRING; a_content: STRING) add_meta_name_content (a_name: STRING; a_content: STRING)
local local
s: STRING_8 s: STRING_8
do do
s := "<meta name=%"" + a_name + "%" content=%"" + a_content + "%" />" s := "<meta name=%"" + a_name + "%" content=%"" + a_content + "%" />"
head_lines.extend (s) add_additional_head_line (s)
end end
add_meta_http_equiv (a_http_equiv: STRING; a_content: STRING) add_meta_http_equiv (a_http_equiv: STRING; a_content: STRING)
@@ -157,39 +162,56 @@ feature -- Element change
s: STRING_8 s: STRING_8
do do
s := "<meta http-equiv=%"" + a_http_equiv + "%" content=%"" + a_content + "%" />" s := "<meta http-equiv=%"" + a_http_equiv + "%" content=%"" + a_content + "%" />"
head_lines.extend (s) add_additional_head_line (s)
end end
add_style (a_href: STRING; a_media: detachable STRING) add_style (a_href: STRING; a_media: detachable STRING)
local local
s: STRING_8 s: STRING_8
do do
s := "<link rel=%"stylesheet%" href=%""+ a_href + "%" type=%"text/css%"" create s.make_from_string ("<link rel=%"stylesheet%" href=%"")
s.append (a_href)
s.append ("%" type=%"text/css%"")
if a_media /= Void then if a_media /= Void then
s.append (" media=%""+ a_media + "%"") s.append (" media=%""+ a_media + "%"")
end end
s.append ("/>") s.append ("/>")
head_lines.extend (s) add_additional_head_line (s)
end
add_style_content (a_style_content: STRING)
-- Add style content `a_style_content' in the head, using <style> tag.
local
s: STRING_8
do
create s.make_from_string ("<style>%N")
s.append (a_style_content)
s.append ("%N</style>")
add_additional_head_line (s)
end end
add_javascript_url (a_src: STRING) add_javascript_url (a_src: STRING)
local local
s: STRING_8 s: STRING_8
do do
s := "<script type=%"text/javascript%" src=%"" + a_src + "%"></script>" create s.make_from_string ("<script type=%"text/javascript%" src=%"")
head_lines.extend (s) s.append (a_src)
s.append ("%"></script>")
add_additional_head_line (s)
end end
add_javascript_content (a_script: STRING) add_javascript_content (a_script: STRING)
local local
s: STRING_8 s: STRING_8
do do
s := "<script type=%"text/javascript%">%N" + a_script + "%N</script>" create s.make_from_string ("<script type=%"text/javascript%">%N")
head_lines.extend (s) s.append (a_script)
s.append ("%N</script>")
add_additional_head_line (s)
end end
note note
copyright: "2011-2014, Jocelyn Fiat, Eiffel Software and others" copyright: "2011-2016, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[ source: "[
Eiffel Software Eiffel Software

View File

@@ -30,7 +30,7 @@ set ROC_TOOL_PATH=%~dp0
goto START goto START
:START :START
echo Calling %ROC_TOOL_PATH%roc.exe %* rem echo Calling %ROC_TOOL_PATH%roc.exe %*
call %ROC_TOOL_PATH%roc.exe %* call %ROC_TOOL_PATH%roc.exe %*
goto END goto END