Added url routing for /files/... and /module/{modname}/files/...

Added CMS_HOOK_RESPONSE_ALTER to give a last chance to alter the response before rendering.
   This hook should not be used, when there are other alternative hook that answer the need, but this is proposed for now, as a way to alter response by adding css, js url, ...
Moved blog under official modules folder.
Cleaned theme of demo example project.
Renamed NODE_MODULE as CMS_NODE_MODULE.
This commit is contained in:
2015-07-01 22:50:19 +02:00
parent 02fe3ba829
commit 42e7763528
57 changed files with 819 additions and 6665 deletions

View File

@@ -16,8 +16,9 @@
<library name="cms_app_env" location="..\..\library\app_env\app_env-safe.ecf" readonly="false"/> <library name="cms_app_env" location="..\..\library\app_env\app_env-safe.ecf" readonly="false"/>
<library name="cms_auth_module" location="..\..\modules\auth\auth-safe.ecf" readonly="false"/> <library name="cms_auth_module" location="..\..\modules\auth\auth-safe.ecf" readonly="false"/>
<library name="cms_basic_auth_module" location="..\..\modules\basic_auth\basic_auth-safe.ecf" readonly="false"/> <library name="cms_basic_auth_module" location="..\..\modules\basic_auth\basic_auth-safe.ecf" readonly="false"/>
<library name="cms_blog_module" location="modules\blog\cms_blog_module-safe.ecf" readonly="false"/> <library name="cms_blog_module" location="..\..\modules\blog\cms_blog_module-safe.ecf" readonly="false"/>
<library name="cms_demo_module" location="modules\demo\cms_demo_module-safe.ecf" readonly="false"/> <library name="cms_demo_module" location="modules\demo\cms_demo_module-safe.ecf" readonly="false"/>
<library name="cms_email_service" location="..\..\library\email\email-safe.ecf" readonly="false"/>
<library name="cms_model" location="..\..\library\model\cms_model-safe.ecf" readonly="false"/> <library name="cms_model" location="..\..\library\model\cms_model-safe.ecf" readonly="false"/>
<library name="cms_node_module" location="..\..\modules\node\node-safe.ecf" readonly="false"/> <library name="cms_node_module" location="..\..\modules\node\node-safe.ecf" readonly="false"/>
<library name="cms_oauth_20_module" location="..\..\modules\oauth20\oauth20-safe.ecf" readonly="false"/> <library name="cms_oauth_20_module" location="..\..\modules\oauth20\oauth20-safe.ecf" readonly="false"/>

View File

@@ -0,0 +1,9 @@
setlocal
set ROC_CMD=%~dp0..\..\tools\roc.exe
set ROC_CMS_DIR=%~dp0
%ROC_CMD% install --module ..\..\modules\auth --dir %ROC_CMS_DIR%
%ROC_CMD% install --module ..\..\modules\basic_auth --dir %ROC_CMS_DIR%
%ROC_CMD% install --module ..\..\modules\node --dir %ROC_CMS_DIR%
%ROC_CMD% install --module ..\..\modules\blog --dir %ROC_CMS_DIR%
%ROC_CMD% install --module ..\..\modules\oauth20 --dir %ROC_CMS_DIR%

File diff suppressed because one or more lines are too long

View File

@@ -1,7 +0,0 @@
<div class='navbar navbar-inverse'>
<div class='navbar-inner nav-collapse' style="height: auto;">
<ul class="nav">
{$header_block/}
</ul>
</div>
</div>

View File

@@ -5,13 +5,14 @@
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<!-- EWF CMS --> <!-- EWF CMS -->
<link rel="stylesheet" href="{$site_url/}theme/css/style.css"> <link rel="stylesheet" href="{$site_url/}theme/css/style.css">
<link rel="stylesheet" href="{$site_url/}theme/css/node.css">
<!-- CMS Blog Module -->
<link rel="stylesheet" href="{$site_url/}theme/css/blog.css">
<!-- jQuery dep -->
<script src="{$site_url/}theme/js/jquery-1.10.2.min.js"></script> <script src="{$site_url/}theme/js/jquery-1.10.2.min.js"></script>
<script src="{$site_url/}theme/js/roc_auth.js"></script>
{if isset="$head"}{$head/}{/if}
{if isset="$styles"}{$styles/}{/if}
{if isset="$scripts"}{$scripts/}{/if}
{if isset="$head_lines"}{$head_lines/}{/if}
<!-- bootstrap framework --> <!-- bootstrap framework -->
<!-- Latest compiled and minified CSS --> <!-- Latest compiled and minified CSS -->

View File

@@ -1 +0,0 @@
<h2>Help Section</h2>

View File

@@ -1 +0,0 @@
<h1>Highlighted Section</h1>

View File

@@ -1,8 +0,0 @@
<div class='span2 sidebar'>
<h3>Left Sidebar</h3>
<ul class="nav nav-tabs nav-stacked">
<li><a href='#'>Another Link 1</a></li>
<li><a href='#'>Another Link 2</a></li>
<li><a href='#'>Another Link 3</a></li>
</ul>
</div>

View File

@@ -1,4 +0,0 @@
<h2>Main Content Section</h2>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum.<p>
<p>Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem. Investigationes demonstraverunt lectores legere me lius quod ii legunt saepius. Claritas est etiam processus dynamicus, qui sequitur mutationem consuetudium lectorum. Mirum est notare quam littera gothica, quam nunc putamus parum claram, anteposuerit litterarum formas humanitatis per seacula quarta decima et quinta decima. Eodem modo typi, qui nunc nobis videntur parum clari, fiant sollemnes in futurum.</p>

View File

@@ -1,9 +0,0 @@
<div id="footer">
<small>
<center>
<p class="text-muted"><a href="#" target="_blank" class="info">ROC Documentation </a>&nbsp;&nbsp;&nbsp;
<a href="http://www.eiffel.com/company/contact/" target="_blank" class="info">Questions? Comments? Let us know! </a></p>
<p>© Copyright 2014 Eiffel Software -- <a href="#" target="_blank" class="info">Privacy Policy</a>
</center>
</small>
</div>

View File

@@ -1,34 +0,0 @@
<div class="navbar navbar-default" role="navigation">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
</button>
<a class="navbar-brand" href="{$site_url/}" itemprop="home" rel="home">{unless isset="$site_name"}Eiffel CMS{/unless}{if isset="$site_name"}{$site_name/}{/if}</a>
</div>
<div class="navbar-collapse collapse">
{if isset="$primary_nav"}
<ul class="nav navbar-nav navbar-left">
{foreach item="item" from="$primary_nav.items"}
<!-- TODO check if a menu item is active or not -->
<li class="active"><a href="{$item.location/}">{$item.title/}</a></li>
{/foreach}
</ul>
{/if}
{if isset="$secondary_nav"}
<ul class="nav navbar-nav navbar-right">
{foreach item="item" from="$secondary_nav.items"}
<!-- TODO check if a menu item is active or not -->
<li class="active"><a href="{$item.location/}">{$item.title/}</a></li>
{/foreach}
</ul>
{/if}
</div>
</div>
</div>

View File

@@ -1,28 +0,0 @@
{if isset="$default_nav"}
<div class="navbar navbar-default" role="navigation">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
</button>
<a class="navbar-brand" href="${site_url/}" itemprop="home" rel="home">{$page_title/}</a>
</div>
<div class="navbar-collapse collapse">
{/if}
{if isset="$primary_nav"}
{$primary_nav/}
{/if}
{if isset="$secondary_nav"}
{$secondary_nav/}
{/if}
{if isset="$default_nav"}
</div>
</div>
</div>
{/if}

View File

@@ -1,6 +0,0 @@
<ul class="nav navbar-nav navbar-left">
{foreach item="item" from="$menu.items"}
<!-- TODO check if a menu item is active or not -->
<li class="active"><a href="{$item.location/}">{$item.title/}</a></li>
{/foreach}
</ul>

View File

@@ -1,8 +0,0 @@
<div class='span2 sidebar'>
<h3>Right Sidebar</h3>
<ul class="nav nav-tabs nav-stacked">
<li><a href='#'>Another Link 1</a></li>
<li><a href='#'>Another Link 2</a></li>
<li><a href='#'>Another Link 3</a></li>
</ul>
</div>

View File

@@ -1,7 +0,0 @@
<ul class="nav navbar-nav navbar-right">
{foreach item="item" from="$menu.items"}
<!-- TODO check if a menu item is active or not -->
<li class="active"><a href="{$item.location/}">{$item.title/}</a></li>
{/foreach}
</ul>

File diff suppressed because it is too large Load Diff

View File

@@ -1,357 +0,0 @@
/*
* Base structure
*/
/* Move down content because we have a fixed navbar that is 36px tall on small screen */
body {
padding-top: 40px;
}
/* On large screen, we give it more space and the navbar is 30px tall. */
@media (min-width: 768px) {
body {
padding-top: 45px;
}
}
/*
* Global add-ons
*/
h1 {
margin-top: initial;
margin-bottom: 5px;
}
h2.sub-header{
margin-top: 1px;
margin-bottom: 1px;
border-bottom: 1px solid #eee;
}
.container .jumbotron {
padding: 10px;
text-align: center;
}
/*
* Sidebar
*/
/* Hide for mobile, show later */
.sidebar {
display: none;
}
@media (min-width: 768px) {
.sidebar {
position: fixed;
top: 0;
left: 0;
bottom: 0;
z-index: 1000;
display: block;
padding: 70px 20px 20px;
background-color: #f5f5f5;
border-right: 1px solid #eee;
}
}
/* Sidebar navigation */
.nav-sidebar {
margin-left: -20px;
margin-right: -21px; /* 20px padding + 1px border */
margin-bottom: 20px;
}
.nav-sidebar > li > a {
padding-left: 20px;
padding-right: 20px;
}
.nav-sidebar > .active > a {
color: #fff;
background-color: #428bca;
}
/*
* Main content
*/
.main {
padding: 3px;
}
@media (min-width: 768px) {
.main {
padding-left: 15px;
padding-right: 15px;
}
}
.main .page-header {
margin-top: 0;
}
/*
* Placeholder dashboard ideas
*/
.placeholders {
margin-bottom: 30px;
text-align: center;
}
.placeholders h4 {
margin-bottom: 0;
}
.placeholder {
margin-bottom: 20px;
}
.placeholder img {
border-radius: 50%;
}
.navbar-default {
background-color:#194573;
border-color: #400040;
}
.navbar-default .navbar-brand {
color: #ffffff;
}
.navbar-default .navbar-brand:hover, .navbar-default .navbar-brand:focus {
color: #ffffff;
}
.navbar-default .navbar-text {
color: #ffffff;
}
.navbar-default .navbar-nav > li > a {
color: #ffffff;
}
.navbar-default .navbar-nav > li > a:hover, .navbar-default .navbar-nav > li > a:focus {
color: #ffffff;
}
.navbar-default .navbar-nav > .active > a, .navbar-default .navbar-nav > .active > a:hover, .navbar-default .navbar-nav > .active > a:focus {
color: #ffffff;
background-color: #400040;
}
.navbar-default .navbar-nav > .open > a, .navbar-default .navbar-nav > .open > a:hover, .navbar-default .navbar-nav > .open > a:focus {
color: #ffffff;
background-color: #400040;
}
.navbar-default .navbar-toggle {
border-color: #400040;
}
.navbar-default .navbar-toggle:hover, .navbar-default .navbar-toggle:focus {
background-color: #400040;
}
.navbar-default .navbar-toggle .icon-bar {
background-color: #ffffff;
}
.navbar-default .navbar-collapse,
.navbar-default .navbar-form {
border-color: #ffffff;
}
.navbar-default .navbar-link {
color: #ffffff;
}
.navbar-default .navbar-link:hover {
color: #ffffff;
}
@media (max-width: 767px) {
.navbar-default .navbar-nav .open .dropdown-menu > li > a {
color: #ffffff;
}
.navbar-default .navbar-nav .open .dropdown-menu > li > a:hover, .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {
color: #ffffff;
}
.navbar-default .navbar-nav .open .dropdown-menu > .active > a, .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover, .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {
color: #ffffff;
background-color: #400040;
}
}
.navbar-nav > li > a {padding-top:5px !important; padding-bottom:5px !important;}
.navbar {min-height:30px !important}
.navbar-brand {
float: left;
padding: 15px;
padding-top: 5px;
padding-right: 15px;
padding-bottom: 5px;
padding-left: 15px;
font-size: 18px;
line-height: 18px;
height: 30px;
}
/* Tooltips */
.blue-tooltip + .tooltip > .tooltip-inner {background-color: #FF;}
.blue-tooltip + .tooltip > .tooltip-arrow { border-bottom-color:#FF; }
.tooltip.top .tooltip-arrow {
bottom: 0;
left: 50%;
margin-left: -5px;
border-top-color: #000000;
border-width: 5px 5px 0;
}
.tooltip-inner {
text-align: left;
color: #000;
background: #fff;
border: solid 1px #000000;
max-width: 450px
}
.tooltip.bottom .tooltip-arrow {
top: 0;
left: 50%;
margin-left: -5px;
border-bottom-color: #000000;
border-width: 0 5px 5px;
}
/* pre */
pre {
word-wrap: code;
white-space: pre-wrap;
background-color:white;
}
/* Container -Fluid */
.container-fluid {
padding: 0 2px;
}
@media (min-width: 768px) {
.container-fluid {
padding: 0 5px;
}
}
.container-fluid .row {
margin: 0px;
}
.row-padding {
margin-top: 25px;
margin-bottom: 25px;
}
/* Width for the text field to enter a bug report number in the reports page.
* We put a maximum width to override the width value coming from `form-control'. */
.form-bug-number-entry {
max-width: 100px;
}
/* Default width for the entries in a table like layout. */
.form-inline .form-control {
width: 95%;
}
.form-inline .checkbox {
font-weight: initial;
vertical-align: top;
}
/* Note that there is also a class called label. */
label {
padding-right: 5px;
}
.label {
padding: 0px;
padding-right: 5px;
}
.label-primary-api-default {
display: inline-block;
width: 105px;
text-align: left;
background: #fff;
color: #000;
font-size: 100%;
text-align: right;
}
.label-primary-api-interactions {
display: inline-block;
padding-right: 5px;
text-align: left;
color: #000;
font-size: 100%;
}
pre {
padding: 1.5px;
display: block;
margin: 0 0 10px;
font-size: 12px;
font-family: monospace;
line-height: 1.428571429;
word-break: break-word;
word-wrap: break-word;
color: #333;
border: 0px;
border-radius: 4px;
}
/* No padding, so that nested columns are always properly aligned. */
.col-xs-1,.col-sm-1,.col-md-1,.col-lg-1,.col-xs-2,.col-sm-2,.col-md-2,.col-lg-2,.col-xs-3,.col-sm-3,.col-md-3,.col-lg-3,.col-xs-4,.col-sm-4,.col-md-4,.col-lg-4,.col-xs-5,.col-sm-5,.col-md-5,.col-lg-5,.col-xs-6,.col-sm-6,.col-md-6,.col-lg-6,.col-xs-7,.col-sm-7,.col-md-7,.col-lg-7,.col-xs-8,.col-sm-8,.col-md-8,.col-lg-8,.col-xs-9,.col-sm-9,.col-md-9,.col-lg-9,.col-xs-10,.col-sm-10,.col-md-10,.col-lg-10,.col-xs-11,.col-sm-11,.col-md-11,.col-lg-11,.col-xs-12,.col-sm-12,.col-md-12,.col-lg-12 {
padding-left: 0px;
padding-right: 0px;
}
.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td {
padding:2px;
vertical-align: middle;
}
.form-control{
height:inherit;
padding: 1px 2px;
margin: 1px;
}
.btn {
padding: 1px 12px;
margin: 1px;
min-width: 100px;
}
.dropdown-toggle, .login {
cursor: pointer;
}
.pager {
margin:10px 0;
}
.pager li>a,.pager li>span {
padding:1px 12px;
border-radius:8px;
}
.well {
padding: 9px;
margin-bottom: 10px;
min-height: 44px;
}
.panel-heading {
background-color: #ddeaf2 !important;
}
.private-panel-border {
border: solid 1px #DBA458 !important;
}
.private-panel {
background-color: #f2eadd !important;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -1,108 +0,0 @@
/*
* EWF CMS javascript based on JQuery
*/
/**
* Override jQuery.fn.init to guard against XSS attacks.
*
* See http://bugs.jquery.com/ticket/9521
*/
(function () {
var jquery_init = jQuery.fn.init;
jQuery.fn.init = function (selector, context, rootjQuery) {
// If the string contains a "#" before a "<", treat it as invalid HTML.
if (selector && typeof selector === 'string') {
var hash_position = selector.indexOf('#');
if (hash_position >= 0) {
var bracket_position = selector.indexOf('<');
if (bracket_position > hash_position) {
throw 'Syntax error, unrecognized expression: ' + selector;
}
}
}
return jquery_init.call(this, selector, context, rootjQuery);
};
jQuery.fn.init.prototype = jquery_init.prototype;
})();
var ROC = ROC || { };
$('body').on('click',"a[rel='node']",function(e){
e.preventDefault();
/*
if uncomment the above line, html5 nonsupported browers won't change the url but will display the ajax content;
if commented, html5 nonsupported browers will reload the page to the specified link.
*/
//get the link location that was clicked
pageurl = $(this).attr('href');
spinner = "<span class='loading'><h3>Loading content..</h3><img src='/static/images/ajax-loader.gif' alt='loading...' class='spinner'></span>";
//to get the ajax content and display in div with class 'main'
$.ajax({url:pageurl+'?rel=node',success: function(data){
$('.main').html(data);
}});
//to change the browser URL to the given link location
//if(pageurl!=window.location){
//window.history.pushState({path:pageurl},'',pageurl);
//}
//stop refreshing to the page given in
return false;
});
$('body').on('click',"a[rel='register']",function(e){
e.preventDefault();
/*
if uncomment the above line, html5 nonsupported browers won't change the url but will display the ajax content;
if commented, html5 nonsupported browers will reload the page to the specified link.
*/
//get the link location that was clicked
pageurl = $(this).attr('href');
spinner = "<span class='loading'><h3>Loading content..</h3><img src='/static/images/ajax-loader.gif' alt='loading...' class='spinner'></span>";
//to get the ajax content and display in div with class 'main'
$.ajax({url:pageurl+'?rel=node',success: function(data){
$('.main').html(data);
}});
//to change the browser URL to the given link location
//if(pageurl!=window.location){
//window.history.pushState({path:pageurl},'',pageurl);
//}
//stop refreshing to the page given in
return false;
});
$("a[rel='node']").click(function(e){
e.preventDefault();
/*
if uncomment the above line, html5 nonsupported browers won't change the url but will display the ajax content;
if commented, html5 nonsupported browers will reload the page to the specified link.
*/
//get the link location that was clicked
pageurl = $(this).attr('href');
spinner = "<span class='loading'><h3>Loading content..</h3><img src='/static/images/ajax-loader.gif' alt='loading...' class='spinner'></span>";
//to get the ajax content and display in div with class 'main'
$.ajax({url:pageurl+'?rel=node',success: function(data){
$('.main').html(data);
}});
//to change the browser URL to the given link location
//if(pageurl!=window.location){
//window.history.pushState({path:pageurl},'',pageurl);
//}
//stop refreshing to the page given in
return false;
});

View File

@@ -55,19 +55,13 @@ feature -- CMS setup
local local
m: CMS_MODULE m: CMS_MODULE
do do
create {NODE_MODULE} m.make (a_setup)
m.enable
a_setup.register_module (m)
create {CMS_AUTHENTICATION_MODULE} m.make create {CMS_AUTHENTICATION_MODULE} m.make
m.enable m.enable
a_setup.register_module (m) a_setup.register_module (m)
create {BASIC_AUTH_MODULE} m.make create {BASIC_AUTH_MODULE} m.make
if not a_setup.module_with_same_type_registered (m) then m.enable
m.enable a_setup.register_module (m)
a_setup.register_module (m)
end
create {CMS_OAUTH_20_MODULE} m.make create {CMS_OAUTH_20_MODULE} m.make
m.enable m.enable
@@ -77,6 +71,14 @@ feature -- CMS setup
m.enable m.enable
a_setup.register_module (m) a_setup.register_module (m)
create {CMS_NODE_MODULE} m.make (a_setup)
m.enable
a_setup.register_module (m)
create {CMS_BLOG_MODULE} m.make
m.enable
a_setup.register_module (m)
create {CMS_DEBUG_MODULE} m.make create {CMS_DEBUG_MODULE} m.make
m.enable m.enable
a_setup.register_module (m) a_setup.register_module (m)
@@ -85,9 +87,6 @@ feature -- CMS setup
m.enable m.enable
a_setup.register_module (m) a_setup.register_module (m)
create {CMS_BLOG_MODULE} m.make
m.enable
a_setup.register_module (m)
end end
end end

View File

@@ -114,10 +114,12 @@ feature -- Hooks
do do
if attached a_response.current_user (a_response.request) as u then if attached a_response.current_user (a_response.request) as u then
create lnk.make (u.name + " (Logout)", "account/roc-logout" ) create lnk.make (u.name + " (Logout)", "account/roc-logout" )
lnk.set_weight (98)
a_menu_system.primary_menu.extend (lnk)
else else
create lnk.make ("Login", "account/roc-login") create lnk.make ("Login", "account/roc-login")
a_menu_system.primary_menu.extend (lnk)
lnk.set_weight (98) lnk.set_weight (98)
a_menu_system.primary_menu.extend (lnk)
if a_response.location.starts_with ("account/") then if a_response.location.starts_with ("account/") then
create lnk.make ("Basic Auth", "account/roc-basic-auth") create lnk.make ("Basic Auth", "account/roc-basic-auth")
lnk.set_expandable (True) lnk.set_expandable (True)
@@ -149,6 +151,7 @@ feature -- Hooks
a_block_id.is_case_insensitive_equal_general ("login") and then a_block_id.is_case_insensitive_equal_general ("login") and then
a_response.location.starts_with ("account/roc-basic-auth") a_response.location.starts_with ("account/roc-basic-auth")
then then
a_response.add_javascript_url (a_response.url ("module/" + name + "/files/js/roc_auth.js", Void))
get_block_view_login (a_block_id, a_response) get_block_view_login (a_block_id, a_response)
elseif elseif
a_block_id.is_case_insensitive_equal_general ("register") and then a_block_id.is_case_insensitive_equal_general ("register") and then
@@ -177,9 +180,16 @@ feature -- Hooks
local local
r: CMS_RESPONSE r: CMS_RESPONSE
do do
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) if attached api.module_by_name ("basic_auth") then
r.set_value ("Login", "optional_content_type") -- FIXME: find better solution to support a default login system.
r.execute create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
r.set_redirection (r.absolute_url ("/account/roc-basic-auth", Void))
r.execute
else
create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api)
r.set_value ("Login", "optional_content_type")
r.execute
end
end end
handle_login_basic_auth (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE) handle_login_basic_auth (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE)

View File

@@ -0,0 +1,321 @@
var ROC_AUTH = ROC_AUTH || { };
var loginURL = "/basic_auth_login";
var logoutURL = "/basic_auth_logoff";
var userAgent = navigator.userAgent.toLowerCase();
var firstLogIn = true;
ROC_AUTH.login = function() {
var form = document.forms[0];
var username = form.username.value;
var password = form.password.value;
//var host = form.host.value;
var origin = window.location.origin.concat(window.location.pathname);
var _login = function(){
if (document.getElementById('myModalFormId') !== null ) {
ROC_AUTH.remove ('myModalFormId');
}
if (username === "" || password === "") {
if (document.getElementById('myModalFormId') === null ) {
var newdiv = document.createElement('div');
newdiv.innerHTML = "<br>Invalid Credentials</br>";
newdiv.id = 'myModalFormId';
$("body").append(newdiv);
}
}else{
//Instantiate HTTP Request
var request = ((window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"));
request.open("GET", loginURL, true, username, password);
request.send(null);
//Process Response
request.onreadystatechange = function(){
if (request.readyState == 4) {
if (request.status==200) {
delete form;
window.location=origin;
}
else{
if (navigator.userAgent.toLowerCase().indexOf("firefox") != -1){
}
if (document.getElementById('myModalFormId') === null ) {
var newdiv = document.createElement('div');
newdiv.innerHTML = "<br>Invalid Credentials</br>";
newdiv.id = 'myModalFormId';
$("body").append(newdiv);
}
}
}
}
}
}
var userAgent = navigator.userAgent.toLowerCase();
if (userAgent.indexOf("firefox") != -1){ //TODO: check version number
if (firstLogIn) _login();
else logoff(_login);
}
else{
_login();
}
if (firstLogIn) firstLogIn = false;
};
ROC_AUTH.login_with_redirect = function() {
var form = document.forms[2];
var username = form.username.value;
var password = form.password.value;
var host = form.host.value;
var _login = function(){
var redirectURL = form.redirect && form.redirect.value || "";
$("#imgProgressRedirect").show();
if (document.getElementById('myModalFormId') !== null ) {
ROC_AUTH.remove ('myModalFormId');
}
if (username === "" || password === "") {
if (document.getElementById('myModalFormId') === null ) {
var newdiv = document.createElement('div');
newdiv.innerHTML = "<br>Invalid Credentials</br>";
newdiv.id = 'myModalFormId';
$("body").append(newdiv);
$("#imgProgressRedirect").hide();
}
}else{
//Instantiate HTTP Request
var request = ((window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"));
request.open("GET", host.concat(loginURL), true, username, password);
request.send(null);
//Process Response
request.onreadystatechange = function(){
if (request.readyState == 4) {
if (request.status==200) {
if (redirectURL === "") {
window.location=host.concat("/");
} else {
window.location=host.concat(redirectURL);
}
}
else{
if (navigator.userAgent.toLowerCase().indexOf("firefox") != -1){
}
if (document.getElementById('myModalFormId') === null ) {
var newdiv = document.createElement('div');
newdiv.innerHTML = "<br>Invalid Credentials</br>";
newdiv.id = 'myModalFormId';
$("body").append(newdiv);
$("#imgProgressRedirect").hide();
}
}
}
}
}
}
var userAgent = navigator.userAgent.toLowerCase();
if (userAgent.indexOf("firefox") != -1){ //TODO: check version number
if (firstLogIn) _login();
else logoff(_login);
}
else{
_login();
}
if (firstLogIn) firstLogIn = false;
};
ROC_AUTH.getQueryParameterByName = function (name) {
name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
results = regex.exec(location.search);
return results === null ? " " : decodeURIComponent(results[1].replace(/\+/g, " "));
}
ROC_AUTH.logoff = function(callback){
var form = document.forms[0];
var host = form.host.value;
if (userAgent.indexOf("msie") != -1) {
document.execCommand("ClearAuthenticationCache");
}
else if (userAgent.indexOf("firefox") != -1){ //TODO: check version number
var request1 = new XMLHttpRequest();
var request2 = new XMLHttpRequest();
//Logout. Tell the server not to return the "WWW-Authenticate" header
request1.open("GET", host.concat(logoutURL) + "?prompt=false", true);
request1.send("");
request1.onreadystatechange = function(){
if (request1.readyState == 4) {
//Sign in with dummy credentials to clear the auth cache
request2.open("GET", host.concat(logoutURL), true, "logout", "logout");
request2.send("");
request2.onreadystatechange = function(){
if (request2.readyState == 4) {
if (callback!=null) { callback.call(); } else { window.location=host.concat(logoutURL);}
}
}
}
}
}
else {
var request = ((window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"));
request.open("GET", host.concat(logoutURL), true, "logout", "logout");
request.send("");
request.onreadystatechange = function(){
if (request.status==401 || request.status==403 ) { window.location=host.concat(logoutURL);
}
}
}
};
ROC_AUTH.remove = function (id)
{
var element = document.getElementById(id);
element.outerHTML = "";
delete element;
return;
};
$(document).ready(function() {
if (typeof String.prototype.contains != 'function') {
String.prototype.contains = function (str){
return this.indexOf(str) != -1;
};
}
ROC_AUTH.progressive_loging();
});
ROC_AUTH.progressive_loging = function () {
ROC_AUTH.login_href();
};
$(document).keypress(function(e) {
if ((e.which === 13) && (e.target.localName === 'input' && e.target.id === 'password')) {
ROC_AUTH.login();
}
});
ROC_AUTH.OnOneClick = function(event) {
event.preventDefault();
if ( document.forms[0] === undefined ) {
ROC_AUTH.create_form();
}
return false;
};
ROC_AUTH.login_href = function() {
var els = document.getElementsByTagName("a");
for (var i = 0, l = els.length; i < l; i++) {
var el = els[i];
if (el.href.contains("/basic_auth_login?destination")) {
loginURL = el.href;
var OneClick = el;
OneClick.addEventListener('click', ROC_AUTH.OnOneClick, false);
}
}
};
ROC_AUTH.create_form = function() {
// Fetching HTML Elements in Variables by ID.
var createform = document.createElement('form'); // Create New Element Form
createform.setAttribute("action", ""); // Setting Action Attribute on Form
createform.setAttribute("method", "post"); // Setting Method Attribute on Form
$("body").append(createform);
var heading = document.createElement('h2'); // Heading of Form
heading.innerHTML = "Login Form ";
createform.appendChild(heading);
var line = document.createElement('hr'); // Giving Horizontal Row After Heading
createform.appendChild(line);
var linebreak = document.createElement('br');
createform.appendChild(linebreak);
var namelabel = document.createElement('label'); // Create Label for Name Field
namelabel.innerHTML = "Username : "; // Set Field Labels
createform.appendChild(namelabel);
var inputelement = document.createElement('input'); // Create Input Field for UserName
inputelement.setAttribute("type", "text");
inputelement.setAttribute("name", "username");
inputelement.setAttribute("required","required");
createform.appendChild(inputelement);
var linebreak = document.createElement('br');
createform.appendChild(linebreak);
var passwordlabel = document.createElement('label'); // Create Label for Password Field
passwordlabel.innerHTML = "Password : ";
createform.appendChild(passwordlabel);
var passwordelement = document.createElement('input'); // Create Input Field for Password.
passwordelement.setAttribute("type", "password");
passwordelement.setAttribute("name", "password");
passwordelement.setAttribute("id", "password");
passwordelement.setAttribute("required","required");
createform.appendChild(passwordelement);
var passwordbreak = document.createElement('br');
createform.appendChild(passwordbreak);
var submitelement = document.createElement('button'); // Append Submit Button
submitelement.setAttribute("type", "button");
submitelement.setAttribute("onclick", "ROC_AUTH.login();");
submitelement.innerHTML = "Sign In ";
createform.appendChild(submitelement);
};
var password = document.getElementById("password")
, confirm_password = document.getElementById("confirm_password");
ROC_AUTH.validatePassword =function(){
if(password.value != confirm_password.value) {
confirm_password.setCustomValidity("Passwords Don't Match");
} else {
confirm_password.setCustomValidity('');
}
}
password.onchange = ROC_AUTH.validatePassword();
confirm_password.onkeyup = ROC_AUTH.validatePassword;

View File

@@ -11,9 +11,9 @@
</option> </option>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/> <library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="base_extension" location="$ISE_LIBRARY\library\base_extension\base_extension-safe.ecf"/> <library name="base_extension" location="$ISE_LIBRARY\library\base_extension\base_extension-safe.ecf"/>
<library name="cms" location="..\..\..\..\cms-safe.ecf" readonly="false"/> <library name="cms" location="..\..\cms-safe.ecf" readonly="false"/>
<library name="cms_model" location="..\..\..\..\library\model\cms_model-safe.ecf" readonly="false"/> <library name="cms_model" location="..\..\library\model\cms_model-safe.ecf" readonly="false"/>
<library name="cms_node_module" location="..\..\..\..\modules\node\node-safe.ecf" readonly="false"/> <library name="cms_node_module" location="..\..\modules\node\node-safe.ecf" readonly="false"/>
<library name="http" location="$ISE_LIBRARY\contrib\library\network\protocol\http\http-safe.ecf"/> <library name="http" location="$ISE_LIBRARY\contrib\library\network\protocol\http\http-safe.ecf"/>
<library name="json" location="$ISE_LIBRARY\contrib\library\text\parser\json\library\json-safe.ecf" readonly="false"/> <library name="json" location="$ISE_LIBRARY\contrib\library\text\parser\json\library\json-safe.ecf" readonly="false"/>
<library name="text_filter" location="$ISE_LIBRARY\unstable\library\text\text_filter\text_filter-safe.ecf"/> <library name="text_filter" location="$ISE_LIBRARY\unstable\library\text\text_filter\text_filter-safe.ecf"/>

View File

@@ -20,6 +20,8 @@ inherit
CMS_HOOK_MENU_SYSTEM_ALTER CMS_HOOK_MENU_SYSTEM_ALTER
CMS_HOOK_RESPONSE_ALTER
create create
make make
@@ -45,11 +47,11 @@ feature {CMS_API} -- Module Initialization
do do
Precursor (api) Precursor (api)
if attached {CMS_NODE_API} api.module_api ({NODE_MODULE}) as l_node_api then if attached {CMS_NODE_API} api.module_api ({CMS_NODE_MODULE}) as l_node_api then
create blog_api.make (api, l_node_api) create blog_api.make (api, l_node_api)
node_api := l_node_api node_api := l_node_api
-- Depends on {NODE_MODULE} -- Depends on {CMS_NODE_MODULE}
create ct create ct
l_node_api.add_content_type (ct) l_node_api.add_content_type (ct)
l_node_api.add_content_type_webform_manager (create {CMS_BLOG_NODE_TYPE_WEBFORM_MANAGER}.make (ct)) l_node_api.add_content_type_webform_manager (create {CMS_BLOG_NODE_TYPE_WEBFORM_MANAGER}.make (ct))
@@ -140,6 +142,12 @@ feature -- Hooks
register_hooks (a_response: CMS_RESPONSE) register_hooks (a_response: CMS_RESPONSE)
do do
a_response.subscribe_to_menu_system_alter_hook (Current) a_response.subscribe_to_menu_system_alter_hook (Current)
a_response.subscribe_to_response_alter_hook (Current)
end
response_alter (a_response: CMS_RESPONSE)
do
a_response.add_style (a_response.url ("/module/" + name + "/files/css/blog.css", Void), Void)
end end
menu_system_alter (a_menu_system: CMS_MENU_SYSTEM; a_response: CMS_RESPONSE) menu_system_alter (a_menu_system: CMS_MENU_SYSTEM; a_response: CMS_RESPONSE)

View File

@@ -0,0 +1,25 @@
ul.cms_blog_nodes {
padding: 0;
margin: 0;
}
ul.cms_blog_nodes li.cms_type_blog {
list-style: none;
display: block;
margin-top: 20px;
padding-bottom: 20px;
border-bottom: 1px dotted black;
}
ul.cms_blog_nodes li.cms_type_blog .blog_title a {
color: black;
font-size: 18px;
text-decoration: none;
display: block;
margin: 6px 0;
}
ul.cms_blog_nodes li.cms_type_blog .blog_title a:hover {
color: #999;
}
ul.cms_blog_nodes li.cms_type_blog .blog_list_summary a {
margin-top: 20px;
display: block;
}

View File

@@ -0,0 +1,30 @@
ul.cms_blog_nodes{
padding:0;
margin:0;
li.cms_type_blog{
list-style: none;
display: block;
margin-top:20px;
padding-bottom:20px;
border-bottom:1px dotted black;
.blog_title a{
color:black;
font-size:18px;
text-decoration: none;
display:block;
margin:6px 0;
&:hover{
color:#999;
}
}
.blog_list_summary a{
margin-top:20px;
display:block;
}
}
}

View File

@@ -16,7 +16,7 @@ inherit
REFACTORING_HELPER REFACTORING_HELPER
create {NODE_MODULE} create {CMS_NODE_MODULE}
make_with_storage make_with_storage
feature {NONE} -- Initialization feature {NONE} -- Initialization

View File

@@ -0,0 +1,227 @@
note
description: "CMS module that bring support for NODE management."
date: "$Date: 2015-02-13 13:08:13 +0100 (ven., 13 févr. 2015) $"
revision: "$Revision: 96616 $"
class
CMS_NODE_MODULE
inherit
CMS_MODULE
redefine
register_hooks,
initialize,
is_installed,
install,
module_api
end
CMS_HOOK_MENU_SYSTEM_ALTER
CMS_HOOK_RESPONSE_ALTER
CMS_HOOK_BLOCK
create
make
feature {NONE} -- Initialization
make (a_setup: CMS_SETUP)
-- Create Current module, disabled by default.
do
version := "1.0"
description := "Service to manage content based on 'node'"
package := "core"
config := a_setup
end
config: CMS_SETUP
-- Node configuration.
feature -- Access
name: STRING = "node"
feature {CMS_API} -- Module Initialization
initialize (a_api: CMS_API)
-- <Precursor>
local
p1,p2: CMS_PAGE
ct: CMS_PAGE_NODE_TYPE
l_node_api: like node_api
l_node_storage: CMS_NODE_STORAGE_I
do
Precursor (a_api)
-- Storage initialization
if attached {CMS_STORAGE_SQL_I} a_api.storage as l_storage_sql then
create {CMS_NODE_STORAGE_SQL} l_node_storage.make (l_storage_sql)
else
-- FIXME: in case of NULL storage, should Current be disabled?
create {CMS_NODE_STORAGE_NULL} l_node_storage.make
end
-- Node API initialization
create l_node_api.make_with_storage (a_api, l_node_storage)
node_api := l_node_api
-- Add support for CMS_PAGE, which requires a storage extension to store the optional "parent" id.
-- For now, we only have extension based on SQL statement.
if attached {CMS_NODE_STORAGE_SQL} l_node_api.node_storage as l_sql_node_storage then
l_sql_node_storage.register_node_storage_extension (create {CMS_NODE_STORAGE_SQL_PAGE_EXTENSION}.make (l_sql_node_storage))
-- FIXME: the following code is mostly for test purpose/initialization, remove later
if l_sql_node_storage.sql_table_items_count ("page_nodes") = 0 then
if attached a_api.user_api.user_by_id (1) as u then
create ct
p1 := ct.new_node (Void)
p1.set_title ("Welcome")
p1.set_content ("Welcome, you are using the ROC Eiffel CMS", Void, Void) -- Use default format
p1.set_author (u)
l_sql_node_storage.save_node (p1)
p2 := ct.new_node (Void)
p2.set_title ("A new page example")
p2.set_content ("This is the content of a page", Void, Void) -- Use default format
p2.set_author (u)
p2.set_parent (p1)
l_sql_node_storage.save_node (p2)
end
end
else
-- FIXME: maybe provide a default solution based on file system, when no SQL storage is available.
-- IDEA: we could also have generic extension to node system, that handle generic addition field.
end
ensure then
node_api_set: node_api /= Void
end
feature {CMS_API} -- Module management
is_installed (a_api: CMS_API): BOOLEAN
-- Is Current module installed?
do
Result := Precursor (a_api)
if Result and attached {CMS_STORAGE_SQL_I} a_api.storage as l_sql_storage then
Result := l_sql_storage.sql_table_exists ("nodes") and
l_sql_storage.sql_table_exists ("page_nodes")
end
end
install (a_api: CMS_API)
do
-- Schema
if attached {CMS_STORAGE_SQL_I} a_api.storage as l_sql_storage then
l_sql_storage.sql_execute_file_script (a_api.module_resource_location (Current, (create {PATH}.make_from_string ("scripts")).extended (name).appended_with_extension ("sql")), Void)
end
Precursor {CMS_MODULE}(a_api)
end
feature {CMS_API} -- Access: API
module_api: detachable CMS_MODULE_API
-- <Precursor>
do
if attached node_api as l_api then
Result := l_api
else
-- Current is initialized, so node_api should be set.
check has_node_api: False end
end
end
node_api: detachable CMS_NODE_API
-- <Precursor>
feature -- Access: router
setup_router (a_router: WSF_ROUTER; a_api: CMS_API)
-- <Precursor>
do
if attached node_api as l_node_api then
configure_web (a_api, l_node_api, a_router)
end
end
configure_web (a_api: CMS_API; a_node_api: CMS_NODE_API; a_router: WSF_ROUTER)
local
l_node_handler: NODE_HANDLER
l_nodes_handler: NODES_HANDLER
l_uri_mapping: WSF_URI_MAPPING
l_trash_handler: TRASH_HANDLER
do
-- TODO: for now, focused only on web interface, add REST api later. [2015-April-29]
create l_node_handler.make (a_api, a_node_api)
create l_uri_mapping.make_trailing_slash_ignored ("/node", l_node_handler)
a_router.map (l_uri_mapping, a_router.methods_get_post)
a_router.handle ("/node/add/{type}", l_node_handler, a_router.methods_get_post)
a_router.handle ("/node/{id}/edit", l_node_handler, a_router.methods_get_post)
a_router.handle ("/node/{id}/delete", l_node_handler, a_router.methods_get_post)
a_router.handle ("/node/{id}/trash", l_node_handler, a_router.methods_get_post)
a_router.handle ("/node/{id}", l_node_handler, a_router.methods_get)
-- For now: no REST API handling... a_router.methods_get_put_delete + a_router.methods_get_post)
-- Nodes
create l_nodes_handler.make (a_api, a_node_api)
create l_uri_mapping.make_trailing_slash_ignored ("/nodes", l_nodes_handler)
a_router.map (l_uri_mapping, a_router.methods_get)
--Trash
create l_trash_handler.make (a_api, a_node_api)
create l_uri_mapping.make_trailing_slash_ignored ("/trash", l_trash_handler)
a_router.map (l_uri_mapping, a_router.methods_get)
end
feature -- Hooks
register_hooks (a_response: CMS_RESPONSE)
-- <Precursor>
do
a_response.subscribe_to_menu_system_alter_hook (Current)
a_response.subscribe_to_block_hook (Current)
a_response.subscribe_to_response_alter_hook (Current)
end
response_alter (a_response: CMS_RESPONSE)
-- <Precursor>
do
a_response.add_style (a_response.url ("/module/" + name + "/files/css/node.css", Void), Void)
end
block_list: ITERABLE [like {CMS_BLOCK}.name]
-- <Precursor>
do
Result := <<"node-info">>
end
get_block_view (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE)
local
-- b: CMS_CONTENT_BLOCK
do
-- create b.make (a_block_id, "Block::node", "This is a block test", Void)
-- a_response.add_block (b, "sidebar_second")
end
menu_system_alter (a_menu_system: CMS_MENU_SYSTEM; a_response: CMS_RESPONSE)
local
lnk: CMS_LOCAL_LINK
-- perms: detachable ARRAYED_LIST [READABLE_STRING_8]
do
create lnk.make ("List of nodes", "nodes")
a_menu_system.primary_menu.extend (lnk)
create lnk.make ("Trash", "trash")
a_menu_system.primary_menu.extend (lnk)
create lnk.make ("Create ..", "node")
a_menu_system.primary_menu.extend (lnk)
end
end

View File

@@ -1,218 +1,18 @@
note note
description: "CMS module that bring support for NODE management." description: "Summary description for {NODE_MODULE}."
date: "$Date: 2015-02-13 13:08:13 +0100 (ven., 13 févr. 2015) $" author: ""
revision: "$Revision: 96616 $" date: "$Date$"
revision: "$Revision$"
class class
NODE_MODULE NODE_MODULE
obsolete "Use {CMS_NODE_MODULE}"
inherit inherit
CMS_NODE_MODULE
CMS_MODULE
redefine
register_hooks,
initialize,
is_installed,
install,
module_api
end
CMS_HOOK_MENU_SYSTEM_ALTER
CMS_HOOK_BLOCK
create create
make make
feature {NONE} -- Initialization
make (a_setup: CMS_SETUP)
-- Create Current module, disabled by default.
do
version := "1.0"
description := "Service to manage content based on 'node'"
package := "core"
config := a_setup
end
config: CMS_SETUP
-- Node configuration.
feature -- Access
name: STRING = "node"
feature {CMS_API} -- Module Initialization
initialize (a_api: CMS_API)
-- <Precursor>
local
p1,p2: CMS_PAGE
ct: CMS_PAGE_NODE_TYPE
l_node_api: like node_api
l_node_storage: CMS_NODE_STORAGE_I
do
Precursor (a_api)
-- Storage initialization
if attached {CMS_STORAGE_SQL_I} a_api.storage as l_storage_sql then
create {CMS_NODE_STORAGE_SQL} l_node_storage.make (l_storage_sql)
else
-- FIXME: in case of NULL storage, should Current be disabled?
create {CMS_NODE_STORAGE_NULL} l_node_storage.make
end
-- Node API initialization
create l_node_api.make_with_storage (a_api, l_node_storage)
node_api := l_node_api
-- Add support for CMS_PAGE, which requires a storage extension to store the optional "parent" id.
-- For now, we only have extension based on SQL statement.
if attached {CMS_NODE_STORAGE_SQL} l_node_api.node_storage as l_sql_node_storage then
l_sql_node_storage.register_node_storage_extension (create {CMS_NODE_STORAGE_SQL_PAGE_EXTENSION}.make (l_sql_node_storage))
-- FIXME: the following code is mostly for test purpose/initialization, remove later
if l_sql_node_storage.sql_table_items_count ("page_nodes") = 0 then
if attached a_api.user_api.user_by_id (1) as u then
create ct
p1 := ct.new_node (Void)
p1.set_title ("Welcome")
p1.set_content ("Welcome, you are using the ROC Eiffel CMS", Void, Void) -- Use default format
p1.set_author (u)
l_sql_node_storage.save_node (p1)
p2 := ct.new_node (Void)
p2.set_title ("A new page example")
p2.set_content ("This is the content of a page", Void, Void) -- Use default format
p2.set_author (u)
p2.set_parent (p1)
l_sql_node_storage.save_node (p2)
end
end
else
-- FIXME: maybe provide a default solution based on file system, when no SQL storage is available.
-- IDEA: we could also have generic extension to node system, that handle generic addition field.
end
ensure then
node_api_set: node_api /= Void
end
feature {CMS_API} -- Module management
is_installed (a_api: CMS_API): BOOLEAN
-- Is Current module installed?
do
Result := Precursor (a_api)
if Result and attached {CMS_STORAGE_SQL_I} a_api.storage as l_sql_storage then
Result := l_sql_storage.sql_table_exists ("nodes") and
l_sql_storage.sql_table_exists ("page_nodes")
end
end
install (a_api: CMS_API)
do
-- Schema
if attached {CMS_STORAGE_SQL_I} a_api.storage as l_sql_storage then
l_sql_storage.sql_execute_file_script (a_api.module_resource_location (Current, (create {PATH}.make_from_string ("scripts")).extended (name).appended_with_extension ("sql")), Void)
end
Precursor {CMS_MODULE}(a_api)
end
feature {CMS_API} -- Access: API
module_api: detachable CMS_MODULE_API
-- <Precursor>
do
if attached node_api as l_api then
Result := l_api
else
-- Current is initialized, so node_api should be set.
check has_node_api: False end
end
end
node_api: detachable CMS_NODE_API
-- <Precursor>
feature -- Access: router
setup_router (a_router: WSF_ROUTER; a_api: CMS_API)
-- <Precursor>
do
if attached node_api as l_node_api then
configure_web (a_api, l_node_api, a_router)
end
end
configure_web (a_api: CMS_API; a_node_api: CMS_NODE_API; a_router: WSF_ROUTER)
local
l_node_handler: NODE_HANDLER
l_nodes_handler: NODES_HANDLER
l_uri_mapping: WSF_URI_MAPPING
l_trash_handler: TRASH_HANDLER
do
-- TODO: for now, focused only on web interface, add REST api later. [2015-April-29]
create l_node_handler.make (a_api, a_node_api)
create l_uri_mapping.make_trailing_slash_ignored ("/node", l_node_handler)
a_router.map (l_uri_mapping, a_router.methods_get_post)
a_router.handle ("/node/add/{type}", l_node_handler, a_router.methods_get_post)
a_router.handle ("/node/{id}/edit", l_node_handler, a_router.methods_get_post)
a_router.handle ("/node/{id}/delete", l_node_handler, a_router.methods_get_post)
a_router.handle ("/node/{id}/trash", l_node_handler, a_router.methods_get_post)
a_router.handle ("/node/{id}", l_node_handler, a_router.methods_get)
-- For now: no REST API handling... a_router.methods_get_put_delete + a_router.methods_get_post)
-- Nodes
create l_nodes_handler.make (a_api, a_node_api)
create l_uri_mapping.make_trailing_slash_ignored ("/nodes", l_nodes_handler)
a_router.map (l_uri_mapping, a_router.methods_get)
--Trash
create l_trash_handler.make (a_api, a_node_api)
create l_uri_mapping.make_trailing_slash_ignored ("/trash", l_trash_handler)
a_router.map (l_uri_mapping, a_router.methods_get)
end
feature -- Hooks
register_hooks (a_response: CMS_RESPONSE)
-- <Precursor>
do
a_response.subscribe_to_menu_system_alter_hook (Current)
a_response.subscribe_to_block_hook (Current)
end
block_list: ITERABLE [like {CMS_BLOCK}.name]
-- <Precursor>
do
Result := <<"node-info">>
end
get_block_view (a_block_id: READABLE_STRING_8; a_response: CMS_RESPONSE)
local
-- b: CMS_CONTENT_BLOCK
do
-- create b.make (a_block_id, "Block::node", "This is a block test", Void)
-- a_response.add_block (b, "sidebar_second")
end
menu_system_alter (a_menu_system: CMS_MENU_SYSTEM; a_response: CMS_RESPONSE)
local
lnk: CMS_LOCAL_LINK
-- perms: detachable ARRAYED_LIST [READABLE_STRING_8]
do
create lnk.make ("List of nodes", "nodes")
a_menu_system.primary_menu.extend (lnk)
create lnk.make ("Trash", "trash")
a_menu_system.primary_menu.extend (lnk)
create lnk.make ("Create ..", "node")
a_menu_system.primary_menu.extend (lnk)
end
end end

View File

@@ -0,0 +1,17 @@
ul.cms-nodes {
list-style-type: none;
padding: 3px 3px 3px 3px;
border: solid 1px #ccc;
}
ul.cms-nodes li {
border-top: dotted 1px #ccc;
}
ul.cms-nodes li:first-child {
border-top: none;
}
ul.cms-nodes li.cms_type_page a::before {
content: "[page] ";
}
ul.cms-nodes li.cms_type_blog a::before {
content: "[blog] ";
}

View File

@@ -0,0 +1,24 @@
ul.cms-nodes {
list-style-type: none;
padding: 3px 3px 3px 3px;
border: solid 1px #ccc;
li{
border-top: dotted 1px #ccc;
&:first-child {
border-top: none;
}
}
li.cms_type_page a::before {
content: "[page] ";
}
li.cms_type_blog a::before {
content: "[blog] ";
}
}

View File

@@ -63,6 +63,14 @@ feature {NONE} -- Initialization
-- Can be also used to precise the "From:" value for email. -- Can be also used to precise the "From:" value for email.
site_email := text_item_or_default ("site.email", "webmaster") site_email := text_item_or_default ("site.email", "webmaster")
-- Location for public files
if attached text_item ("files-dir") as s then
create files_location.make_from_string (s)
else
files_location := site_location.extended ("files")
end
-- Location for modules folders. -- Location for modules folders.
if attached text_item ("modules-dir") as s then if attached text_item ("modules-dir") as s then
create modules_location.make_from_string (s) create modules_location.make_from_string (s)

View File

@@ -95,6 +95,9 @@ feature -- Access: Theme
site_location: PATH site_location: PATH
-- Path to CMS site root dir. -- Path to CMS site root dir.
files_location: PATH
-- Path to public "files" dir.
modules_location: PATH modules_location: PATH
-- Path to modules. -- Path to modules.

View File

@@ -0,0 +1,31 @@
note
description: "[
Hook providing a way to alter the cms response itself.
It is recommanded to use finer cms hook, but this hook is quite general.
]"
date: "$Date: 2014-11-13 16:23:47 +0100 (jeu., 13 nov. 2014) $"
revision: "$Revision: 96085 $"
deferred class
CMS_HOOK_RESPONSE_ALTER
inherit
CMS_HOOK
feature -- Hook
response_alter (a_response: CMS_RESPONSE)
deferred
end
note
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software
5949 Hollister Ave., Goleta, CA 93117 USA
Telephone 805-685-1006, Fax 805-685-6869
Website http://www.eiffel.com
Customer support http://support.eiffel.com
]"
end

View File

@@ -347,6 +347,12 @@ feature -- Environment/ theme
Result := setup.site_location Result := setup.site_location
end end
files_location: PATH
-- CMS public files location.
do
Result := setup.files_location
end
theme_location: PATH theme_location: PATH
-- Active theme location. -- Active theme location.
do do

View File

@@ -164,7 +164,19 @@ feature -- Settings: router
end) end)
a_router.handle ("/theme/", fhdl, router.methods_GET) a_router.handle ("/theme/", fhdl, router.methods_GET)
-- "/files/.."
create fhdl.make_hidden_with_path (api.files_location)
fhdl.disable_index
fhdl.set_not_found_handler (agent (ia_uri: READABLE_STRING_8; ia_req: WSF_REQUEST; ia_res: WSF_RESPONSE)
do
execute_default (ia_req, ia_res)
end)
a_router.handle ("/files/", fhdl, router.methods_GET)
-- files folder from specific module.
a_router.handle ("/module/{modname}/files{/vars}", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent handle_module_files), a_router.methods_get)
-- www folder. Should we keep this??
create fhdl.make_hidden_with_path (setup.environment.www_path) create fhdl.make_hidden_with_path (setup.environment.www_path)
fhdl.disable_index fhdl.disable_index
fhdl.set_not_found_handler (agent (ia_uri: READABLE_STRING_8; ia_req: WSF_REQUEST; ia_res: WSF_RESPONSE) fhdl.set_not_found_handler (agent (ia_uri: READABLE_STRING_8; ia_req: WSF_REQUEST; ia_res: WSF_RESPONSE)
@@ -263,6 +275,27 @@ feature -- Execution
end end
end end
handle_module_files (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Handle files per modules.
-- i.e: "/module/{modname}/files{/vars}"
local
fhdl: WSF_FILE_SYSTEM_HANDLER
r: NOT_FOUND_ERROR_CMS_RESPONSE
do
if attached {WSF_STRING} req.path_parameter ("modname") as l_mod_name then
create fhdl.make_with_path (api.module_location_by_name (l_mod_name.url_encoded_value).extended ("files"))
fhdl.disable_index
fhdl.set_not_found_handler (agent (ia_uri: READABLE_STRING_8; ia_req: WSF_REQUEST; ia_res: WSF_RESPONSE)
do
execute_default (ia_req, ia_res)
end)
fhdl.execute_starts_with ("/module/" + l_mod_name.url_encoded_value + "/files/", req, res)
else
create r.make (req, res, api)
r.execute
end
end
execute_default (req: WSF_REQUEST; res: WSF_RESPONSE) execute_default (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Default request handler if no other are relevant -- Default request handler if no other are relevant
local local
@@ -274,7 +307,7 @@ feature -- Execution
end end
note note
copyright: "2011-2014, Jocelyn Fiat, Eiffel Software and others" copyright: "2011-2015, 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

@@ -613,6 +613,28 @@ feature -- Hook: value alter
end end
end end
feature -- Hook: response
subscribe_to_response_alter_hook (h: CMS_HOOK_RESPONSE_ALTER)
-- Add `h' as subscriber of response alter hooks CMS_HOOK_RESPONSE_ALTER.
do
subscribe_to_hook (h, {CMS_HOOK_RESPONSE_ALTER})
end
invoke_response_alter (a_response: CMS_RESPONSE)
-- Invoke value table alter hook for table `a_table'.
do
if attached hook_subscribers.item ({CMS_HOOK_RESPONSE_ALTER}) as lst then
across
lst as c
loop
if attached {CMS_HOOK_RESPONSE_ALTER} c.item as h then
h.response_alter (a_response)
end
end
end
end
feature -- Hook: menu_system_alter feature -- Hook: menu_system_alter
subscribe_to_menu_system_alter_hook (h: CMS_HOOK_MENU_SYSTEM_ALTER) subscribe_to_menu_system_alter_hook (h: CMS_HOOK_MENU_SYSTEM_ALTER)
@@ -868,6 +890,9 @@ feature -- Generation
common_prepare (page) common_prepare (page)
custom_prepare (page) custom_prepare (page)
-- Cms response
invoke_response_alter (Current)
-- Cms values -- Cms values
invoke_value_table_alter (values) invoke_value_table_alter (values)
@@ -1132,4 +1157,7 @@ feature {NONE} -- Execution
end end
note
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end end

View File

@@ -30,8 +30,9 @@ feature -- Execution
process process
-- Computed response message. -- Computed response message.
do do
-- set_title ("CMS")
-- set_page_title (Void)
end end
note
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end end