changeset 11:573272ec604b

almost comlete doxygen library
author sergey
date Thu, 15 May 2014 18:24:02 +0400
parents 83ad674a8cdd
children d9551c7e7101
files config/Benzin.Web.Application.xml lib/Implab/Web/Resources/Root.pm public_html/static/css/forms.css public_html/static/css/global.css public_html/static/css/index.css shared_view/includes/dojo/context.tt shared_view/includes/dojo/form.tt shared_view/includes/dojo/form/Button.tt shared_view/includes/dojo/form/CheckboxSelect.tt shared_view/includes/dojo/form/DateTextBox.tt shared_view/includes/dojo/form/Input.tt shared_view/includes/dojo/group.tt shared_view/includes/form/box.tt shared_view/includes/form/group.tt shared_view/includes/form/locale/ru/box.s shared_view/includes/menu.tt shared_view/includes/menu/menubar.tt shared_view/includes/templates/User.tt shared_view/includes/templates/locale/ru/User.s shared_view/includes/templates/plain.tt view/layout/default/base.tt view/layout/default/index.tt view/layout/default/library.tt view/layout/dojo.tt view/layout/init.tt view/site/index.tt view/site/user.tt view/site/user/edit.tt view/site/user/locale/ru/edit.s view/site/user/locale/ru/pagemenu.s view/site/user/locale/ru/passwd.s view/site/user/locale/ru/register.s view/site/user/login.tt view/site/user/pagemenu.tt view/site/user/passwd.tt view/site/user/register.tt
diffstat 36 files changed, 693 insertions(+), 37 deletions(-) [+]
line wrap: on
line diff
--- a/config/Benzin.Web.Application.xml	Thu May 15 01:51:42 2014 +0400
+++ b/config/Benzin.Web.Application.xml	Thu May 15 18:24:02 2014 +0400
@@ -23,8 +23,7 @@
 		<item type="IMPL::Web::Handler::RestController">
 
 			<!-- Корневой ресурс -->
-			<resourceFactory>Benzin::Web::Resources::RootResource
-			</resourceFactory>
+			<resourceFactory>Implab::Web::Resources::Root</resourceFactory>
 		</item>
 
 		<!-- Представления -->
@@ -61,7 +60,7 @@
 						<COMPILE_DIR>/tmp/ttc</COMPILE_DIR>
 					</options>
 					<includes type='ARRAY'>
-						<item>components</item>
+						<item>includes</item>
 					</includes>
 					<globals id="globals" type="HASH">
 						<cdn type="IMPL::Config::Include">cdn.xml</cdn>
--- a/lib/Implab/Web/Resources/Root.pm	Thu May 15 01:51:42 2014 +0400
+++ b/lib/Implab/Web/Resources/Root.pm	Thu May 15 18:24:02 2014 +0400
@@ -4,7 +4,8 @@
 use IMPL::declare {
 	require => {
 		LibraryResource => '-Benzin::Web::Resources::Doxygen::Library',
-		UserResource => '-Benzin::Web::Resources::UserResource'
+		UserResource => '-Benzin::Web::Resources::UserResource',
+		Sec => 'IMPL::Security'
 	},
 	base => [
 		'IMPL::Web::Application::Resource' => '@_'
@@ -12,11 +13,17 @@
 };
 
 sub children {
+	my $this = shift;
 	return {
 		library => {
-			class => LibraryResource
+			class => LibraryResource,
+			connection => $this->application->connections->{doxLibrary}
 		},
 		user => {
+			model => sub {
+				Sec->principal;
+			},
+			role => 'user',
 			class => UserResource,
 			components => [qw(login logout passwd edit)]
 		}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/public_html/static/css/forms.css	Thu May 15 18:24:02 2014 +0400
@@ -0,0 +1,139 @@
+/**************** BLACK BLOCK ****************/
+
+.float-left {
+	float: left;
+}
+
+.black-block {
+	background-color: black;
+	margin: 3px;
+}
+
+.black-block .content {
+	margin: 5px 0;
+	color: #ffffff;
+	border-left: 6px solid black;
+	padding: 10px 10px 10px 5px;
+	display: inline-block;
+}
+
+.black-block.green .content  {
+	border-left: 6px #007000 solid;
+}
+
+.black-block.blue .content  {
+    border-left: 6px #004070 solid;
+}
+
+.black-block a {
+	text-transform: uppercase;
+	text-decoration: none;
+}
+
+.black-block.green a:hover {
+    border-left: 6px #00ff00 solid;
+}
+
+.black-block.blue a:hover {
+    border-left: 6px #0070ff solid;
+}
+
+/* forms */
+
+.form-error {
+	padding: 3px 3px 3px 21px;
+	background: #ffc0c0 url('warning-icon-small.png') 2px 2px no-repeat;
+	color: #900000;
+	border: 1px solid #900000
+}
+
+.control-errors {
+    color: #900000;
+    font-style: italic;
+}
+
+.tundra .dijitValidationTextBoxError .dijitValidationIcon {
+	background: url('warning-icon-small.png') no-repeat scroll center center transparent;
+}
+
+/* box form  */
+
+.input-control,
+.control-content,
+.control-label {
+    position: relative;
+}
+
+.box-form {
+    margin: 50px auto;
+    width: 300px;
+    border: 1px solid #000000;
+}
+
+.box-form .content {
+    padding: 10px;
+}
+
+.box-form .title {
+    background-color: #000000;
+    padding: 10px;
+    color: #ffffff;
+    font-size: 120%;
+    text-transform: uppercase;
+    font-weight: bold;
+}
+
+.box-form .dijitTextBox {
+    padding: 3px;
+    position: relative;
+    left: 0px;
+    right: 10px;
+    width: 100%;
+}
+
+.box-form .input-control .control-content {
+	padding-right: 8px;
+}
+
+
+.box-form .control-label {
+	padding: 3px 0;
+}
+
+.box-form .control-title {
+    text-transform: uppercase;
+}
+
+.box-form .dijitButtonActive .dijitButtonNode,
+.box-form .dijitButtonHover .dijitButtonNode,
+.box-form .dijitButtonNode {
+	padding: 5px 0;
+	border: none;
+	background: #000000;
+	color: #f0f0f0;
+}
+
+.box-form .dijitButtonContents {
+    border-left: 5px solid #c0c0c0;
+    padding: 2px 10px 2px 5px;
+    transition: all 0.5s;
+}
+
+.box-form .dijitButtonActive .dijitButtonContents,
+.box-form .dijitButtonHover .dijitButtonContents {
+    border-left: 5px solid #00ff00;
+}
+
+/*************** DISPLAY FORM *******************/
+
+.propertyGroup {
+    margin: 10px 0;
+}
+
+.propertyDisplay {
+    margin: 0 15px 0 0;
+}
+
+.propertyValue {
+    font-weight: bold;
+}
\ No newline at end of file
--- a/public_html/static/css/global.css	Thu May 15 01:51:42 2014 +0400
+++ b/public_html/static/css/global.css	Thu May 15 18:24:02 2014 +0400
@@ -1,4 +1,6 @@
 html, body {
+	font-family: arial;
+    font-size: 10pt;
     height: 100%;
     margin: 0;
     padding: 0;
@@ -39,7 +41,7 @@
     line-height: 100%;
 }
 
-ul.menu-bar li.menu-item {
+.menu-bar .menu-item {
 	padding: 5px;
 	text-decoration: none;
 	padding-bottom: 8px;
@@ -85,4 +87,12 @@
 {
 	font-weight: bold;
 	text-align: right;
+}
+
+/*************************** LAYOUT *******************************************/
+
+#header {
+	padding: 0px 30px;
+	border-bottom: 1px solid #c0c0c0;
+	box-shadow: 0 7px 15px -10px rgba(0, 0, 0, 0.6);
 }
\ No newline at end of file
--- a/public_html/static/css/index.css	Thu May 15 01:51:42 2014 +0400
+++ b/public_html/static/css/index.css	Thu May 15 18:24:02 2014 +0400
@@ -1,5 +1,6 @@
 
 .wrapper {
+	position: relative;
     height: 100%;
     margin: 0 auto;
     white-space: nowrap;
@@ -56,7 +57,7 @@
 
 ul.tile-menu li:hover a {
     display: inline-block;
-    background: #b0b0b0;
+    background: #c0c0c0;
     box-shadow: 0 30px 15px -10px rgba(0, 0, 0, 0.6);
     top: -20px;
     /*padding: 15px;*/
@@ -66,7 +67,11 @@
     white-space: nowrap;
     font-weight: normal;
     font-size: 10pt;
-    color: #0f0f0f;
+    color: #404040;
+}
+
+ul.tile-menu li:hover a .foot {
+	color: #0f0f0f;
 }
 
 ul.tile-menu li a .label {
@@ -75,27 +80,27 @@
     transition: all 0.5s;
 }
 
-ul.tile-menu li a.green:hover .label {
+ul.tile-menu li:hover a.green .label {
     color: #afffcf;
 }
 
-ul.tile-menu li a.blue:hover .label {
+ul.tile-menu li:hover a.blue .label {
     color: #afdfff;
 }
 
-ul.tile-menu li a.red:hover .label {
+ul.tile-menu li:hover a.red .label {
     color: #ffafaf;
 }
 
-ul.tile-menu li a.orange:hover .label {
+ul.tile-menu li:hover a.orange .label {
     color: #ffdfaf;
 }
 
-ul.tile-menu li a.orange:hover .label {
+ul.tile-menu li:hover a.orange .label {
     color: #ffdfaf;
 }
 
-ul.tile-menu li a.magenta:hover .label {
+ul.tile-menu li:hover a.magenta .label {
 	color: #ffafff;
 }
 
@@ -103,3 +108,23 @@
     font-family: Arial;
     font-size: 32pt;
 }
+
+#top-menu {
+	position: absolute;
+	top: 0px;
+	right: 20px;
+	padding: 0px 30px;
+	border-bottom: 1px solid #c0c0c0;
+	box-shadow: 0 7px 15px -10px rgba(0, 0, 0, 0.6);
+}
+
+#top-menu .menu-bar a,
+#top-menu .menu-bar .menu-item {
+	border: none;
+	padding: 5px;
+}
+
+#top-menu .menu-bar a:hover {
+	background: black;
+	color: white;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/shared_view/includes/dojo/context.tt	Thu May 15 18:24:02 2014 +0400
@@ -0,0 +1,25 @@
+[%  META activation = 'singleton' class='Benzin::Web::View::DojoContext';
+    
+    JSON = import('JSON');
+    MACRO ToJSON(arg) GET JSON.new.utf8(1).encode(arg);
+    
+    theme = this.theme || 'tundra';
+    config = this.config || {};
+    dijitCss = cdn.dojo.dijit.themes.$theme.$theme.SetView('css');
+    dojoCss = cdn.dojo.dojo.resources.dojo.SetView('css');
+    dojoJs = cdn.dojo.Clone.SetView('js');
+%]
+<link type="text/css" rel="stylesheet" href="$dojoCss"/>
+<link type="text/css" rel="stylesheet" href="$dijitCss"/>
+<script type="text/javascript">
+    var dojoConfig = [% ToJSON(config) %]
+</script>
+<script type="text/javascript" src="$dojoJs.dojo.dojo"></script>
+<script type="text/javascript">
+    [%
+        IF config.parseOnLoad;
+            this.AddJsModule('dojo/parser');
+        END;
+        'require(' _ ToJSON(this.modules) _ ');';
+    +%]
+</script>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/shared_view/includes/dojo/form.tt	Thu May 15 18:24:02 2014 +0400
@@ -0,0 +1,21 @@
+[%
+	BLOCK INIT;
+		document.dojo.modules.push("dijit/form/Form");
+	END;
+	
+	FormResult = import('IMPL::Web::View::FormResult');
+	Metadata = import('IMPL::Web::View::Metadata::FormMeta');
+	
+	UNLESS is(model,FormResult);
+		THROW form 'The form result is required';
+	END;
+	
+	# defaults
+	content = layout.content || 'form/group';
+	enctype = enctype || 'application/x-www-form-urlencoded';
+	method = method || 'POST';
+	formMeta = Metadata.GetMetadataForModel(model.node, errors = model.errors, nodes = [model.node]);
+ %]
+<form data-dojo-type="dijit/form/Form" class="form-control" method="$method" [% IF action %]action="$action" [% END %] enctype="$enctype">
+	[% display_model(formMeta, content, layout.args) %]
+</form>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/shared_view/includes/dojo/form/Button.tt	Thu May 15 18:24:02 2014 +0400
@@ -0,0 +1,4 @@
+[% BLOCK INIT;
+	document.dojo.modules.push("dijit/form/Button");
+END %]
+<input data-dojo-type="dijit/form/Button" type="[% type || 'button' %]" [% IF name %] name="$name"[% END %] [% IF text %] label="$text" value="$text"[% END %]/>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/shared_view/includes/dojo/form/CheckboxSelect.tt	Thu May 15 18:24:02 2014 +0400
@@ -0,0 +1,33 @@
+[%
+	BLOCK INIT;
+    	document.dojo.modules.push("dijit/form/CheckBox");
+    END;
+    IF metadata.inputType == 'password';
+    	value = '';
+    ELSE;
+    	value = metadata.inputValue;
+    END;
+    
+    selected = {};
+    
+    FOREACH item IN metadata.inputValue;
+    	selected.${item} = 1;
+    END;
+    
+    options = [];
+    valueField = "roleName";
+    labelField = "roleName";
+    
+    FOREACH item IN resource.GetDataSource(metadata.GetSchemaProperty('data-source-name')).data;
+    	options.push({
+    		label = item.$labelField,
+    		value = item.$valueField,
+    		selected = selected.${item.$labelField}
+    	});
+    END; 
+%]
+[% FOREACH option IN options %]
+	<div>
+		<input type="checkbox" name="$prefix" value="$option.value"[% IF option.selected %] checked="true"[% END %]/><span>$option.label</span>
+	</div>
+[% END %]
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/shared_view/includes/dojo/form/DateTextBox.tt	Thu May 15 18:24:02 2014 +0400
@@ -0,0 +1,6 @@
+[% META class='IMPL::Web::View::InputControl';
+
+    dojo = require('dojo/context').new();
+    dojo.AddJsModule("dijit/form/DateTextBox");
+%]
+<input data-dojo-type="dijit/form/DateTextBox" id="$this.id-input" name="$this.inputName" type="date" [% IF NOT this.decl.isOptional %]required="true"[% END %] value="$this.value.ymd" />
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/shared_view/includes/dojo/form/Input.tt	Thu May 15 18:24:02 2014 +0400
@@ -0,0 +1,11 @@
+[%
+	BLOCK INIT;
+    	document.dojo.modules.push("dijit/form/ValidationTextBox");
+    END;
+    IF metadata.inputType == 'password';
+    	value = '';
+    ELSE;
+    	value = metadata.inputValue;
+    END;
+%]
+<input data-dojo-type="dijit/form/ValidationTextBox" id="$id" name="$prefix" type="$metadata.inputType" [% IF NOT metadata.isOptional %]required="true"[% END %] value="$value" />
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/shared_view/includes/dojo/group.tt	Thu May 15 18:24:02 2014 +0400
@@ -0,0 +1,39 @@
+[% META class='IMPL::Web::View::TTFormContainer' %]
+[% BLOCK ITEM %]
+    <div id="$control.id" class="input-control">
+        <div class="control-label">
+            [% this.Include('ITEM_LABEL') %]
+            [% this.Include('ITEM_ERRORS') %]
+        </div>
+        <div class="control-content">
+            $control.Render
+        </div>
+    </div>
+[% END %]
+[% BLOCK ITEM_ERRORS %]
+    <span class="control-errors">[% control.errors.join(', ') %]</span>
+[% END %]
+[% BLOCK ITEM_LABEL %]
+    [% control.GetSchemaProp('display') %]
+[% END %]
+[% BLOCK ERRORS %]
+    <span class="control-errors">[% this.GetOwnErrors().join(', ') %]</span>
+[% END %]
+[% BLOCK LAYOUT %]
+    <div id="$this.id" class="group-control">
+        [% this.Include('ERRORS') %]
+        <div class="control-label">
+            [% this.GetSchemaProp('display') %]
+        </div>
+        <div class="control-content">
+            [% this.Include('CONTENT') %]
+            <br style="clear: both;" />
+        </div>
+    </div>    
+[% END %]
+[% BLOCK CONTENT;
+    FOREACH ctl IN this.GetChildControls();
+        this.Include('ITEM', control = ctl);
+    END;
+END %]
+[% this.Include('LAYOUT') %]
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/shared_view/includes/form/box.tt	Thu May 15 18:24:02 2014 +0400
@@ -0,0 +1,45 @@
+[% labels(
+	InvalidForm = 'Invalid form data, please review.'
+)%]
+[% MACRO element(control) BLOCK;
+	ers = control.GetOwnErrors().join(', ');
+%]
+<div class='input-control'>
+	<div class='control-label'>
+		[% control.label %][% IF ers %] <span class="control-errors">$ers</span>[% END %]
+	</div>
+	<div class='control-content'>
+		[% display_model(control, path = control.name) %]
+	</div>
+</div>
+[% END %]
+[% BLOCK CONTENT %]
+	[% element(prop) FOREACH prop IN metadata.GetProperties() %]
+[% END %]
+[% BLOCK FOOTER %]
+	[% render('dojo/form/Button', button) FOREACH button IN buttons %]
+[% END %]
+<script type="dojo/on" data-dojo-event="submit">
+	if(!this.validate()){
+    	alert('$InvalidForm');
+        return false;
+    }
+    return true;
+</script>
+<div class="box-form">
+    <div class="title">$document.title</div>
+    <div class="content">
+		<div class="group-control">
+			[% FOR error IN metadata.GetOwnErrors() %]
+			<div class="control-errors">$error</div>
+			[% END %]
+			<div class="control-content">
+		    	[% INCLUDE CONTENT %]
+		    	<br style="clear:both">
+		    </div>
+		    <div class="form-footer">
+				[% INCLUDE FOOTER %]
+			</div>
+		</div>
+    </div>
+</div>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/shared_view/includes/form/group.tt	Thu May 15 18:24:02 2014 +0400
@@ -0,0 +1,20 @@
+[%
+	META class='form'
+%]
+[% MACRO element(control) BLOCK;
+	ers = errors(control).join(', ');
+%]
+<div class='input-control'>
+	<div class='control-label'>
+		[% label(control) %][% IF ers %] <span class="control-errors">$ers</span>[% END %]
+	</div>
+	<div class='control-content'>
+		[% display_for(control) %]
+	</div>
+</div>
+[% END %]
+
+[% element(child.name) FOREACH child IN children %]
+<div class="form-footer">
+	[% render('dojo/form/Button', button) FOREACH button IN buttons %]
+</div>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/shared_view/includes/form/locale/ru/box.s	Thu May 15 18:24:02 2014 +0400
@@ -0,0 +1,1 @@
+InvalidForm = Проверьте правильность заполнения формы.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/shared_view/includes/menu.tt	Thu May 15 18:24:02 2014 +0400
@@ -0,0 +1,12 @@
+[% META class='IMPL::Web::View::TTMenuControl' %]
+[% MACRO link(href,title) BLOCK %]
+<a href="$href">$title</a>
+[%- END %]
+[% MACRO span(title) BLOCK %]
+<span class="menu-item">$title</span>
+[%- END %]
+<ul class="$class" id="$id">
+[% FOREACH item IN items %]
+    <li [% IF item.active %]class="active"[% END %]>[% item.href ? link(item.href,item.title) : span(item.title) %]</li>
+[% END %]
+</ul>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/shared_view/includes/menu/menubar.tt	Thu May 15 18:24:02 2014 +0400
@@ -0,0 +1,9 @@
+<ul class="menu-bar $class">
+	[% FOREACH item IN model -%]
+		<li>
+			[% IF item.href %]
+				<a href="$item.href">
+			[% END %]
+		</li>
+	[%- END %]
+</ul>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/shared_view/includes/templates/User.tt	Thu May 15 18:24:02 2014 +0400
@@ -0,0 +1,65 @@
+[%
+	BLOCK INIT;
+		document.css.push( app.location.css.Child('display-float.css') );
+	END;
+	labels({
+		fullNameLabel = 'Full name',
+		uidLabel = 'User ID',
+		gecosLabel = 'Description',
+		mailLabel = 'eMail',
+		givenNameLabel = 'Given name',
+		telephoneNumberLabel = 'Phone',
+		roomNumberLabel = 'Room',
+		departmentNumberLabel = 'Department',
+		RolesLabel = 'Roles'
+	});
+%]
+[% MACRO element(field) BLOCK %]
+	<div class="field">
+		<span class="field-name">[% ${"${field}Label"} %]</span>
+		<span class="field-value">[% display_for(field) %]</span>
+	</div>
+[% END %]
+<div class="float object-data">
+	[%
+		FOREACH field IN [
+		    'uid',
+		    'fullName'
+		];
+			element(field) IF model.${field};
+		END;
+	%]
+	<br style="clear:both"/>
+</div>
+<div class="float object-data">
+	[%
+		FOREACH field IN [
+			'gecos',
+			'mail',
+			'telephoneNumber',
+			'roomNumber',
+			'departmentNumber'
+		];
+			element(field) IF model.${field};
+		END;
+	%]
+	<br style="clear:both"/>
+</div>
+[% IF showRoles %]
+	<div class="float object-data">
+		[%
+			roles = [];
+			FOREACH role IN security.roles.Query(member = model).data;
+				roles.push(role.description || role.roleName);
+			END;
+		%]
+		<div class="field">
+			<span class="field-name">$RolesLabel</span>
+			<span class="field-value">[% roles.join(', ')%]</span>
+		</div>
+		<br style="clear:both"/>
+	</div>
+[% END %]
+<div class="align-right comment">
+	<small>LDAP record</small>
+</div>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/shared_view/includes/templates/locale/ru/User.s	Thu May 15 18:24:02 2014 +0400
@@ -0,0 +1,9 @@
+fullNameLabel = Полное имя
+uidLabel = Идентификатор
+gecosLabel = Описание
+mailLabel = eMail
+givenNameLabel = Имя
+telephoneNumberLabel = Телефон
+roomNumberLabel = Комната №
+departmentNumberLabel = Подразделение
+RolesLabel = Роли
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/shared_view/includes/templates/plain.tt	Thu May 15 18:24:02 2014 +0400
@@ -0,0 +1,1 @@
+<span class="plain">$model</span>
\ No newline at end of file
--- a/view/layout/default/base.tt	Thu May 15 01:51:42 2014 +0400
+++ b/view/layout/default/base.tt	Thu May 15 18:24:02 2014 +0400
@@ -1,4 +1,39 @@
 [%
 	document.css.push(css.global);
+	document.css.push(css.forms);
 %]
+[% IF document.menu.page.size;
+	render('menu', items = document.menu.page, class='menu-bar', id='page-menu');
+END %]
+<div id="header">
+	[%
+		render(
+			'menu',
+			items = [
+				{ title = 'HOME', href = app.location },
+				{ title = 'Wiki', href = app.location.wiki },
+				{ title = 'Owncloud', href = app.location.owncloud },
+				{ title = 'BugZilla', href = app.location.bugzilla },
+				{ title = 'Library', href = app.location.library },
+				{ title = 'Mercurial', href = app.location.mercurial }
+			],
+			class = 'menu-bar float-left',
+			id = 'main-menu'
+	)%]
+	[%
+		IF user.isNobody;
+			usermenu = [
+				{ title = 'Login', href= app.location.user.login(ref = location) }
+			];
+		ELSE;
+			usermenu = [
+				{ title = user.name },
+				{ title = 'Settings', href = app.location.user },
+				{ title = 'Logout', href = app.location.user.logout }
+			];
+		END;
+		render('menu', items = usermenu, class = 'menu-bar float-right', id = 'user-menu');
+	%]
+	<div style="clear: both"></div>
+</div>
 $content
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/view/layout/default/index.tt	Thu May 15 18:24:02 2014 +0400
@@ -0,0 +1,23 @@
+[%
+	document.css.push(css.global);
+	document.css.push(css.forms);
+	docuemnt.css.push(css.index);
+%]
+<div class="wrapper">
+	<div class="inline-ghost"> </div>
+	<div class="page">
+	$content
+	</div>
+</div>
+<div id="top-menu">
+	<ul class="menu-bar float-right">
+		[% IF user.isNobody %]
+			<li><a href="$app.location.user.login?ref=$location">Login</a></li>
+		[% ELSE %]
+		<!-- no space
+		--><li class="menu-item">$user.name</li><!-- no space
+		--><li class=""><a href="$app.location.user">Settings</a><!--
+		--><li class=""><a href="$app.location.user.logout">Logout</a></li>
+		[% END %]
+	</ul>
+</div>
\ No newline at end of file
--- a/view/layout/default/library.tt	Thu May 15 01:51:42 2014 +0400
+++ b/view/layout/default/library.tt	Thu May 15 18:24:02 2014 +0400
@@ -2,7 +2,7 @@
 	labels(
 		CollectionTitle = "Home (%name%)"
 	);
-	document.postRender.push('dojo');
+	document.dojo.enable = 1;
 	
 	document.css.push(css.library);
 	
@@ -54,7 +54,10 @@
 		[% END %]
 	</ul>
 [% END %]
-[% BLOCK LAYOUT %]
+[% BLOCK LAYOUT;
+	render('base', content = content);
+END %]
+[% WRAPPER LAYOUT %]
 <div class="library-pane">
 	
 	<div id="toc-nav" class="nav-pane left">
@@ -91,7 +94,4 @@
 		});
 	</script>
 </div>
-[% END %]
-[% WRAPPER LAYOUT;
-	render('base', content = content);
-END %]
\ No newline at end of file
+[% END %]
\ No newline at end of file
--- a/view/layout/dojo.tt	Thu May 15 01:51:42 2014 +0400
+++ b/view/layout/dojo.tt	Thu May 15 18:24:02 2014 +0400
@@ -1,15 +1,20 @@
-[%
-	modules = document.dojo.modules.unique;
+[% IF document.dojo.enable || document.dojo.modules.size;
+	IF document.dojo.config.parseOnLoad;
+		document.dojo.modules.push('dojo/parser');
+	END;
+	mods = document.dojo.modules.unique;
 	style = document.dojo.style || 'tundra';
 	dojo.js = cdn.dojo.SetView('js').dojo.dojo;
     dijit.css = cdn.dojo.dijit.themes.${style}.${style}.SetView('css');
     dojo.css = cdn.dojo.dojo.resources.dojo.SetView('css');
     
-	document.css.push(dojo.css);
-	document.css.push(dijit.css);
+    document.class.push('tundra'); 
+    
+	document.css.unshift(dojo.css);
+	document.css.unshift(dijit.css);
 	document.scripts.push({ text = 'dojoConfig = ' _ toJSON(document.dojo.config) _ ';' });
 	document.scripts.push({ src = dojo.js });
-	IF modules.size;
-		document.scripts.push({ text = "require(" _ toJSON(modules) _ ");"});
+	IF mods.size;
+		document.scripts.push({ text = "require(" _ toJSON(mods) _ ");"});
 	END;
-%]
\ No newline at end of file
+END %]
\ No newline at end of file
--- a/view/layout/init.tt	Thu May 15 01:51:42 2014 +0400
+++ b/view/layout/init.tt	Thu May 15 18:24:02 2014 +0400
@@ -9,4 +9,5 @@
             ]
 		}
 	};
+	document.postRender.push('dojo');
 %]
\ No newline at end of file
--- a/view/site/index.tt	Thu May 15 01:51:42 2014 +0400
+++ b/view/site/index.tt	Thu May 15 18:24:02 2014 +0400
@@ -1,15 +1,9 @@
 [%
 	document.title = "HOME";
+	document.layout = 'index';
 	document.css.push(css.index);
 %]
-<div class="wrapper">
-	<ul class="menu-bar float-right"><!-- no space
-		--><li class="menu-item">user</li><!-- no space
-		--><li class=""><a href="#">exit</a></li>
-	</ul>
-	<div style="clear:both"></div>
-	<div class="inline-ghost"> </div>
-	<div class="page">
+
 		<ul id="main-menu" class="tile-menu"><!-- no space
 			--><li><a href="$app.location.wiki" class="green"><span class="label">Wiki</span><br /><span class="foot">База знаний</span></a></li><!-- no space
 			--><li><a href="$app.location.owncloud" class="blue"><span class="label">Owncloud</span><br /><span class="foot">Персональное облако</span></a></li><!-- no space
@@ -17,5 +11,3 @@
 			--><li><a href="$app.location.library" class="magenta"><span class="label">Library</span><br /><span class="foot">Документация</span></a></li><!-- no space
 			--><li><a href="https://hg.implab.org" class="orange"><span class="label">Mercurial</span><br /><span class="foot">Исходные коды</span></a></li>
 		</ul>
-	</div>
-</div>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/view/site/user.tt	Thu May 15 18:24:02 2014 +0400
@@ -0,0 +1,8 @@
+[%
+	render('user/pagemenu');
+	labels(
+		Title = 'User profile (%user%)'
+	);
+    document.title = Title(user = user.name);
+    display_model(model, showRoles = 1);
+%]
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/view/site/user/edit.tt	Thu May 15 18:24:02 2014 +0400
@@ -0,0 +1,19 @@
+[%
+	labels(
+		Title = 'Update profile',
+		BtnSubmit = 'Save' 
+	);
+    document.title = Title;
+    render('pagemenu');
+	display_model(
+		result,
+		'dojo/form',
+		layout = {
+			content = 'form/box',
+			args = {
+				title = Title,
+				buttons = [ { type='submit', text= BtnSubmit } ]
+			}
+		},
+	)
+%]
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/view/site/user/locale/ru/edit.s	Thu May 15 18:24:02 2014 +0400
@@ -0,0 +1,2 @@
+Title = Редактирование профиля
+BtnSubmit = Сохранить
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/view/site/user/locale/ru/pagemenu.s	Thu May 15 18:24:02 2014 +0400
@@ -0,0 +1,3 @@
+ViewProfile = Профиль
+EditProfile = Обновить профиль
+ChangePass  = Сменить пароль
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/view/site/user/locale/ru/passwd.s	Thu May 15 18:24:02 2014 +0400
@@ -0,0 +1,3 @@
+Title = Сменить пароль
+BtnSubmit = Сменить
+SuccessMessage = Пароль для пользователя %name% успешно изменен!
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/view/site/user/locale/ru/register.s	Thu May 15 18:24:02 2014 +0400
@@ -0,0 +1,2 @@
+Title = Регистрация
+BtnSubmit = Зарегистрироваться
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/view/site/user/login.tt	Thu May 15 18:24:02 2014 +0400
@@ -0,0 +1,19 @@
+[%
+	labels(
+		Title = 'Login'
+		BtnSubmit = 'Login'
+	);
+    document.title = Title;
+
+	display_model(
+		result,
+		'dojo/form',
+		layout = {
+			content = 'form/box',
+			args = {
+				title = Title
+				buttons = [ { type='submit', text= BtnSubmit } ],
+			}
+		}
+	);
+%]
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/view/site/user/pagemenu.tt	Thu May 15 18:24:02 2014 +0400
@@ -0,0 +1,14 @@
+[%
+	labels(
+		ViewProfile = 'View profile'
+		EditProfile = 'Update profile'
+		ChangePass  = 'Change password' 
+	);
+	userLocation = resource.Seek('user').location;
+    document.menu.page = [
+        { title = ViewProfile, href = userLocation },
+        { title = EditProfile, href = userLocation.edit },
+        { title = ChangePass, href = userLocation.passwd }
+    ];
+    
+%]
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/view/site/user/passwd.tt	Thu May 15 18:24:02 2014 +0400
@@ -0,0 +1,29 @@
+[%
+	labels(
+		Title = 'Change password'
+		BtnSubmit = 'Change',
+		SuccessMessage = 'Пароль для пользователя %name% успешно изменен!'
+	);
+    document.title = Title;
+	render('pagemenu');
+	
+	IF result.complete;
+%]
+	<h3 class='success'>
+    	[% SuccessMessage(model) %] 
+	</h3>
+[%	
+	ELSE;
+		display_model(
+			result,
+			'dojo/form',
+			layout = {
+				content = 'form/box',
+				args = {
+					title = Title,
+					buttons = [ { type = 'submit', text = BtnSubmit } ]
+				}
+			}
+		);
+	END;
+%]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/view/site/user/register.tt	Thu May 15 18:24:02 2014 +0400
@@ -0,0 +1,20 @@
+[%
+	labels(
+		Title = 'Register'
+		BtnSubmit = 'Register'
+	);
+	document.title = Title;
+	display_model(
+		result,
+		'dojo/form',
+		layout = {
+			content = 'form/box',
+			args = {
+				title = Title,
+				buttons = [
+					{ type = 'submit', text = BtnSubmit }
+				]
+			}
+		}
+	);
+%]
\ No newline at end of file