Many updates

This commit is contained in:
Eugene ;) 2020-04-13 00:21:36 +02:00
parent a02b607bc6
commit 87754c8e06
23 changed files with 1256 additions and 124 deletions

View File

@ -1,16 +0,0 @@
@page "/counter"
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}

View File

@ -0,0 +1,7 @@
@page "/dmesg"
<h3>Dmesg</h3>
@code {
}

View File

@ -1,46 +0,0 @@
@page "/fetchdata"
@using Seenginx.Data
@inject WeatherForecastService ForecastService
<h1>Weather forecast</h1>
<p>This component demonstrates fetching data from a service.</p>
@if (forecasts == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
}
@code {
private WeatherForecast[] forecasts;
protected override async Task OnInitializedAsync()
{
forecasts = await ForecastService.GetForecastAsync(DateTime.Now);
}
}

View File

@ -0,0 +1,7 @@
@page "/nginx"
<h3>Nginx</h3>
@code {
}

View File

@ -0,0 +1,7 @@
@page "/systemd"
<h3>SystemD</h3>
@code {
}

View File

@ -13,15 +13,17 @@
<link rel="icon" href="~/favicon.png" />
<title>Seenginx</title>
<base href="~/" />
<link rel="stylesheet" href="~/css/side-menu.css" asp-append-version="true" />
<environment include="Staging,Production">
<link rel="stylesheet" href="~/css/open-iconic.min.css" />
<link rel="stylesheet" href="~/css/pure.min.css" />
<link rel="stylesheet" href="~/css/open-iconic.min.css" asp-append-version="true" />
<link rel="stylesheet" href="~/css/pure.min.css" asp-append-version="true" />
<link rel="stylesheet" href="~/css/main.min.css" asp-append-version="true" />
</environment>
<environment include="Development">
<link rel="stylesheet" href="~/css/open-iconic.css" />
<link rel="stylesheet" href="~/css/pure.css" />
<link rel="stylesheet" href="~/css/open-iconic.css" asp-append-version="true" />
<link rel="stylesheet" href="~/css/pure.css" asp-append-version="true" />
<link rel="stylesheet" href="~/css/main.css" asp-append-version="true" />
</environment>
<link href="css/site.css" rel="stylesheet" />
</head>
<body>
<app>
@ -40,5 +42,7 @@
</div>
<script src="_framework/blazor.server.js"></script>
<script src="js/modal.js" asp-append-version="true"></script>
<script src="js/ui.js" asp-append-version="true"></script>
</body>
</html>

26
Seenginx/SCSS/base.scss Normal file
View File

@ -0,0 +1,26 @@
body {
box-sizing: border-box
}
*, ::before, ::after {
box-sizing: inherit
}
#blazor-error-ui {
background: lightyellow;
bottom: 0;
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
display: none;
left: 0;
padding: 0.6rem 1.25rem 0.7rem 1.25rem;
position: fixed;
width: 100%;
z-index: 1000;
& .dismiss {
cursor: pointer;
position: absolute;
right: 0.75rem;
top: 0.5rem;
}
}

4
Seenginx/SCSS/main.scss Normal file
View File

@ -0,0 +1,4 @@
@import "mixins.scss";
@import "base.scss";
@import "utility.scss";
@import "side-menu.scss";

58
Seenginx/SCSS/mixins.scss Normal file
View File

@ -0,0 +1,58 @@
//MEDIA QUERY MANAGER
/*$breakpoint argument choices:
- phone
- tab-port
- tab-land
- desk
- big-desktop
*/
@mixin MediaQuery($breakpoint) {
// max-width:600px;
@if $breakpoint==phone {
@media only screen and (max-width: 37.5em) {
@content
}
}
@if $breakpoint==tab-p {
// min-width:601px;
// max-width:900px;
@media only screen and (min-width: 601px) and (max-width: 900px) {
@content
}
}
@if $breakpoint==tab-l {
// min-width:901px;
// max-width:1200px;
@media only screen and (min-width: 901px) and (max-width: 1200px) {
@content
}
}
@if $breakpoint==laptop {
// min-width:1201px;
// max-width:1366px;
@media only screen and (min-width: 1201px) and (max-width: 1366px) {
@content
}
}
@if $breakpoint==desk {
// min-width:1201px;
// max-width:1800px;
@media only screen and (min-width: 1201px) and (max-width: 1800px) {
@content
}
}
@if $breakpoint==big-d {
// min-width:1801px;
// max-width:4000px;
@media only screen and (min-width: 1801px) and (max-width: 4000px) {
@content
}
}
}

View File

@ -0,0 +1,182 @@
body {
color: #777;
}
:root {
--leftPanel: 150px;
--negativeLeftPanel: -150px;
--mobileLeftPanel: 150px;
--mobileNegativeLeftPanel: -150px;
}
.pure-img-responsive {
max-width: 100%;
height: auto;
}
/*
Add transition to containers so they can push in and out.
*/
#layout,
#menu,
.menu-link {
-webkit-transition: all 0.2s ease-out;
-moz-transition: all 0.2s ease-out;
-ms-transition: all 0.2s ease-out;
-o-transition: all 0.2s ease-out;
transition: all 0.2s ease-out;
}
/*
This is the parent `<div>` that contains the menu and the content area.
*/
#layout {
position: relative;
left: 0;
padding-left: 0;
&.active {
& .menu-link {
left: var(--leftPanel);
}
& #menu {
left: var(--leftPanel);
width: var(--leftPanel);
}
}
}
/*
The `#menu` `<div>` is the parent `<div>` that contains the `.pure-menu` that
appears on the left side of the page.
*/
#menu {
margin-left: var(--negativeLeftPanel); /* "#menu" width */
width: var(--leftPanel);
position: fixed;
top: 0;
left: 0;
bottom: 0;
z-index: 1000; /* so the menu or its navicon stays above all content */
background: #191818;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
//All anchors inside the menu should be styled like this.
& a {
color: #999;
border: none;
padding: 0.6em 0 0.6em 0.6em;
}
//Remove all background/borders, since we are applying them to #menu.
& .pure-menu,
& .pure-menu ul {
border: none;
background: transparent;
}
//Add that light border to separate items into groups.
& .pure-menu ul,
& .pure-menu .menu-item-divided {
border-top: 1px solid #333;
}
//Change color of the anchor links on hover/focus.
& .pure-menu li a:hover,
& .pure-menu li a:focus {
background: #333;
}
//This styles the selected menu item `<li>`.
& .pure-menu-selected,
& .pure-menu-heading {
background: #1f8dd6;
}
//This styles a link within a selected menu item `<li>`.
& .pure-menu-selected a {
color: #fff;
}
//This styles the menu heading.
& .pure-menu-heading {
font-size: 110%;
color: #fff;
margin: 0;
}
}
/* -- Dynamic Button For Responsive Menu -------------------------------------*/
/*
The button to open/close the Menu is custom-made and not part of Pure. Here's
how it works:
*/
/*
`.menu-link` represents the responsive menu toggle that shows/hides on
small screens.
*/
.menu-link {
position: fixed;
display: block; /* show this only on small screens */
top: 0;
left: 0; /* "#menu width" */
background: #000;
background: rgba(0,0,0,0.7);
font-size: 16px; /* change this value to increase/decrease button size */
z-index: 10;
width: min-content;
height: auto;
padding: 14px;
&:hover,
&:focus {
background: #000;
}
}
/* -- Responsive Styles (Media Queries) ------------------------------------- */
/*
Hides the menu at `48em`, but modify this based on your app's needs.
*/
@media (min-width: 48em) {
.header,
.content {
padding-left: 2em;
padding-right: 2em;
}
#layout {
padding-left: var(--leftPanel); /* left col width "#menu" */
left: 0;
}
#menu {
left: var(--leftPanel);
}
.menu-link {
position: fixed;
left: var(--leftPanel);
display: none;
}
#layout.active .menu-link {
left: var(--leftPanel);
}
}
@media (max-width: 48em) {
/* Only apply this when the window is small. Otherwise, the following
case results in extra padding on the left:
* Make the window small.
* Tap the menu to trigger the active state.
* Make the window large again.
*/
#layout.active {
position: relative;
left: var(--leftPanel);
}
}

View File

@ -0,0 +1,9 @@
.isHidden {
display: none;
&Mobile {
@include MediaQuery(phone) {
display: none
}
}
}

View File

@ -5,8 +5,28 @@
</PropertyGroup>
<ItemGroup>
<Folder Include="wwwroot\fonts\" />
<Content Remove="compilerconfig.json" />
</ItemGroup>
<ItemGroup>
<Content Include="SCSS\side-menu.scss" />
</ItemGroup>
<ItemGroup>
<Folder Include="wwwroot\images\" />
</ItemGroup>
<ItemGroup>
<None Include="compilerconfig.json" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="3.1.3" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.1.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Seenginx.Models\Seenginx.Models.csproj" />
</ItemGroup>
</Project>

View File

@ -1,15 +1,14 @@
@inherits LayoutComponentBase
<div class="sidebar">
<NavMenu />
<div id="layout" class="@MenuActiveClass">
<NavMenu @bind-MenuActiveClass="MenuActiveClass" />
<div id="main">
@Body
</div>
</div>
<div class="main">
<div class="top-row px-4">
<a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
</div>
<div class="content px-4">
@Body
</div>
</div>
@code{
public string MenuActiveClass { get; set; } = null;
}

View File

@ -1,37 +1,36 @@
<div class="top-row pl-4 navbar navbar-dark">
<a class="navbar-brand" href="">Seenginx</a>
<button class="navbar-toggler" @onclick="ToggleNavMenu">
<span class="navbar-toggler-icon"></span>
</button>
</div>
@inherits NavMenuBase
<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
<ul class="nav flex-column">
<li class="nav-item px-3">
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
<span class="oi oi-home" aria-hidden="true"></span> Home
</NavLink>
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" href="counter">
<span class="oi oi-plus" aria-hidden="true"></span> Counter
</NavLink>
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" href="fetchdata">
<span class="oi oi-list-rich" aria-hidden="true"></span> Fetch data
</NavLink>
</li>
</ul>
</div>
<a href="#menu" id="menuLink" class="menu-link @MenuActiveClass" @onclick="ToggleMenu">
<span class="oi" data-glyph="menu"></span>
</a>
@code {
private bool collapseNavMenu = true;
<div id="menu" class="@MenuActiveClass">
<div class="pure-menu">
<NavLink class="pure-menu-heading" href="/" Match="NavLinkMatch.All">
<span class="oi" data-glyph="bolt"></span>
<span class="isHiddenMobile">Seenginx</span>
</NavLink>
private string NavMenuCssClass => collapseNavMenu ? "collapse" : null;
<ul class="pure-menu-list">
<li class="pure-menu-item @ActiveNav.GetValueOrDefault("nginx")">
<NavLink href="/nginx" class="pure-menu-link" @onclick="@(e => SelectMenuItem("nginx"))">
<span class="oi" data-glyph="code"></span>
<span class="isHiddenMobile">NGINX</span>
</NavLink>
</li>
<li class="pure-menu-item @ActiveNav.GetValueOrDefault("systemd")">
<NavLink href="/systemd" class="pure-menu-link" @onclick="@(e => SelectMenuItem("systemd"))">
<span class="oi" data-glyph="cog"></span>
<span class="isHiddenMobile">SystemD</span>
</NavLink>
</li>
private void ToggleNavMenu()
{
collapseNavMenu = !collapseNavMenu;
}
}
<li class="pure-menu-item @ActiveNav.GetValueOrDefault("dmesg")">
<NavLink href="/dmesg" class="pure-menu-link" @onclick="@(e => SelectMenuItem("dmesg"))">
<span class="oi" data-glyph="dashboard"></span>
<span class="isHiddenMobile">Dmesg</span>
</NavLink>
</li>
</ul>
</div>
</div>

View File

@ -0,0 +1,47 @@
using Microsoft.AspNetCore.Components;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Seenginx.Shared
{
public class NavMenuBase : ComponentBase
{
protected Dictionary<string, string> ActiveNav { get; set; }
public bool CollapsePanel { get; set; } = false;
[Parameter]
public string MenuActiveClass { get; set; }
[ParameterAttribute]
public EventCallback<string> MenuActiveClassChanged { get; set; }
protected async override Task OnInitializedAsync()
{
ActiveNav = new Dictionary<string, string>
{
{ "nginx", null },
{ "systemd", null },
{ "dmesg", null }
};
await base.OnInitializedAsync();
}
protected void SelectMenuItem(string menuItem)
{
foreach (var key in ActiveNav.Keys.ToArray())
ActiveNav[key] = null;
ActiveNav[menuItem] = "pure-menu-selected";
}
protected async Task ToggleMenu()
{
CollapsePanel = !CollapsePanel;
MenuActiveClass = CollapsePanel ? "active" : null;
await MenuActiveClassChanged.InvokeAsync(MenuActiveClass);
StateHasChanged();
}
}
}

View File

@ -8,7 +8,6 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Seenginx.Data;
using Seenginx.Services;
namespace Seenginx
@ -26,11 +25,15 @@ namespace Seenginx
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddRazorPages()
#if DEBUG
.AddRazorRuntimeCompilation()
#endif
;
services.AddServerSideBlazor();
services.AddTransient<IDmesgService,DmesgService>();
services.AddTransient<INginxService,NginxService>();
services.AddTransient<ISystemDService,SystemDService>();
services.AddTransient<IDmesgService, DmesgService>();
services.AddTransient<INginxService, NginxService>();
services.AddTransient<ISystemDService, SystemDService>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.

View File

@ -0,0 +1,6 @@
[
{
"outputFile": "wwwroot/css/main.css",
"inputFile": "SCSS/main.scss"
}
]

View File

@ -0,0 +1,63 @@
{
"compilers": {
"less": {
"autoPrefix": "",
"cssComb": "none",
"ieCompat": true,
"strictMath": false,
"strictUnits": false,
"relativeUrls": true,
"rootPath": "",
"sourceMapRoot": "",
"sourceMapBasePath": "",
"sourceMap": false
},
"sass": {
"autoPrefix": "",
"includePath": "",
"indentType": "space",
"indentWidth": 2,
"outputStyle": "nested",
"Precision": 5,
"relativeUrls": true,
"sourceMapRoot": "",
"lineFeed": "",
"sourceMap": false
},
"stylus": {
"sourceMap": false
},
"babel": {
"sourceMap": false
},
"coffeescript": {
"bare": false,
"runtimeMode": "node",
"sourceMap": false
},
"handlebars": {
"root": "",
"noBOM": false,
"name": "",
"namespace": "",
"knownHelpersOnly": false,
"forcePartial": false,
"knownHelpers": [],
"commonjs": "",
"amd": false,
"sourceMap": false
}
},
"minifiers": {
"css": {
"enabled": true,
"termSemicolons": true,
"gzip": false
},
"javascript": {
"enabled": true,
"termSemicolons": true,
"gzip": false
}
}
}

View File

@ -0,0 +1,173 @@
/*$breakpoint argument choices:
- phone
- tab-port
- tab-land
- desk
- big-desktop
*/
body {
box-sizing: border-box; }
*, ::before, ::after {
box-sizing: inherit; }
#blazor-error-ui {
background: lightyellow;
bottom: 0;
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
display: none;
left: 0;
padding: 0.6rem 1.25rem 0.7rem 1.25rem;
position: fixed;
width: 100%;
z-index: 1000; }
#blazor-error-ui .dismiss {
cursor: pointer;
position: absolute;
right: 0.75rem;
top: 0.5rem; }
.isHidden {
display: none; }
@media only screen and (max-width: 37.5em) {
.isHiddenMobile {
display: none; } }
body {
color: #777; }
:root {
--leftPanel: 150px;
--negativeLeftPanel: -150px;
--mobileLeftPanel: 150px;
--mobileNegativeLeftPanel: -150px; }
.pure-img-responsive {
max-width: 100%;
height: auto; }
/*
Add transition to containers so they can push in and out.
*/
#layout,
#menu,
.menu-link {
-webkit-transition: all 0.2s ease-out;
-moz-transition: all 0.2s ease-out;
-ms-transition: all 0.2s ease-out;
-o-transition: all 0.2s ease-out;
transition: all 0.2s ease-out; }
/*
This is the parent `<div>` that contains the menu and the content area.
*/
#layout {
position: relative;
left: 0;
padding-left: 0; }
#layout.active .menu-link {
left: var(--leftPanel); }
#layout.active #menu {
left: var(--leftPanel);
width: var(--leftPanel); }
/*
The `#menu` `<div>` is the parent `<div>` that contains the `.pure-menu` that
appears on the left side of the page.
*/
#menu {
margin-left: var(--negativeLeftPanel);
/* "#menu" width */
width: var(--leftPanel);
position: fixed;
top: 0;
left: 0;
bottom: 0;
z-index: 1000;
/* so the menu or its navicon stays above all content */
background: #191818;
overflow-y: auto;
-webkit-overflow-scrolling: touch; }
#menu a {
color: #999;
border: none;
padding: 0.6em 0 0.6em 0.6em; }
#menu .pure-menu,
#menu .pure-menu ul {
border: none;
background: transparent; }
#menu .pure-menu ul,
#menu .pure-menu .menu-item-divided {
border-top: 1px solid #333; }
#menu .pure-menu li a:hover,
#menu .pure-menu li a:focus {
background: #333; }
#menu .pure-menu-selected,
#menu .pure-menu-heading {
background: #1f8dd6; }
#menu .pure-menu-selected a {
color: #fff; }
#menu .pure-menu-heading {
font-size: 110%;
color: #fff;
margin: 0; }
/* -- Dynamic Button For Responsive Menu -------------------------------------*/
/*
The button to open/close the Menu is custom-made and not part of Pure. Here's
how it works:
*/
/*
`.menu-link` represents the responsive menu toggle that shows/hides on
small screens.
*/
.menu-link {
position: fixed;
display: block;
/* show this only on small screens */
top: 0;
left: 0;
/* "#menu width" */
background: #000;
background: rgba(0, 0, 0, 0.7);
font-size: 16px;
/* change this value to increase/decrease button size */
z-index: 10;
width: min-content;
height: auto;
padding: 14px; }
.menu-link:hover, .menu-link:focus {
background: #000; }
/* -- Responsive Styles (Media Queries) ------------------------------------- */
/*
Hides the menu at `48em`, but modify this based on your app's needs.
*/
@media (min-width: 48em) {
.header,
.content {
padding-left: 2em;
padding-right: 2em; }
#layout {
padding-left: var(--leftPanel);
/* left col width "#menu" */
left: 0; }
#menu {
left: var(--leftPanel); }
.menu-link {
position: fixed;
left: var(--leftPanel);
display: none; }
#layout.active .menu-link {
left: var(--leftPanel); } }
@media (max-width: 48em) {
/* Only apply this when the window is small. Otherwise, the following
case results in extra padding on the left:
* Make the window small.
* Tap the menu to trigger the active state.
* Make the window large again.
*/
#layout.active {
position: relative;
left: var(--leftPanel); } }

1
Seenginx/wwwroot/css/main.min.css vendored Normal file
View File

@ -0,0 +1 @@
body{box-sizing:border-box;}*,::before,::after{box-sizing:inherit;}#blazor-error-ui{background:#ffffe0;bottom:0;box-shadow:0 -1px 2px rgba(0,0,0,.2);display:none;left:0;padding:.6rem 1.25rem .7rem 1.25rem;position:fixed;width:100%;z-index:1000;}#blazor-error-ui .dismiss{cursor:pointer;position:absolute;right:.75rem;top:.5rem;}.isHidden{display:none;}@media only screen and (max-width:37.5em){.isHiddenMobile{display:none;}}body{color:#777;}:root{--leftPanel:150px;--negativeLeftPanel:-150px;--mobileLeftPanel:150px;--mobileNegativeLeftPanel:-150px;}.pure-img-responsive{max-width:100%;height:auto;}#layout,#menu,.menu-link{-webkit-transition:all .2s ease-out;-moz-transition:all .2s ease-out;-ms-transition:all .2s ease-out;-o-transition:all .2s ease-out;transition:all .2s ease-out;}#layout{position:relative;left:0;padding-left:0;}#layout.active .menu-link{left:var(--leftPanel);}#layout.active #menu{left:var(--leftPanel);width:var(--leftPanel);}#menu{margin-left:var(--negativeLeftPanel);width:var(--leftPanel);position:fixed;top:0;left:0;bottom:0;z-index:1000;background:#191818;overflow-y:auto;-webkit-overflow-scrolling:touch;}#menu a{color:#999;border:none;padding:.6em 0 .6em .6em;}#menu .pure-menu,#menu .pure-menu ul{border:none;background:transparent;}#menu .pure-menu ul,#menu .pure-menu .menu-item-divided{border-top:1px solid #333;}#menu .pure-menu li a:hover,#menu .pure-menu li a:focus{background:#333;}#menu .pure-menu-selected,#menu .pure-menu-heading{background:#1f8dd6;}#menu .pure-menu-selected a{color:#fff;}#menu .pure-menu-heading{font-size:110%;color:#fff;margin:0;}.menu-link{position:fixed;display:block;top:0;left:0;background:#000;background:rgba(0,0,0,.7);font-size:16px;z-index:10;width:min-content;height:auto;padding:14px;}.menu-link:hover,.menu-link:focus{background:#000;}@media(min-width:48em){.header,.content{padding-left:2em;padding-right:2em;}#layout{padding-left:var(--leftPanel);left:0;}#menu{left:var(--leftPanel);}.menu-link{position:fixed;left:var(--leftPanel);display:none;}#layout.active .menu-link{left:var(--leftPanel);}}@media(max-width:48em){#layout.active{position:relative;left:var(--leftPanel);}}

View File

@ -1,7 +0,0 @@
body {
box-sizing: border-box
}
*, ::before, ::after {
box-sizing: inherit
}

View File

@ -0,0 +1,540 @@
/*!
* CSS Modal
* http://drublic.github.com/css-modal
*
* @author Hans Christian Reinl - @drublic
*/
(function (global, $) {
'use strict';
/*
* Storage for functions and attributes
*/
var modal = {
activeElement: undefined, // Store for currently active element
lastActive: undefined, // Store for last active elemet
stackedElements: [], // Store for stacked elements
// All elements that can get focus, can be tabbed in a modal
tabbableElements: 'a[href], area[href], input:not([disabled]),' +
'select:not([disabled]), textarea:not([disabled]),' +
'button:not([disabled]), iframe, object, embed, *[tabindex],' +
'*[contenteditable]',
/*
* Polyfill addEventListener for IE8 (only very basic)
* @param event {string} event type
* @param element {Node} node to fire event on
* @param callback {function} gets fired if event is triggered
*/
on: function (event, elements, callback) {
var i = 0;
if (typeof event !== 'string') {
throw new Error('Type error: `event` has to be a string');
}
if (typeof callback !== 'function') {
throw new Error('Type error: `callback` has to be a function');
}
if (!elements) {
return;
}
// Make elements an array and attach event listeners
if (!elements.length) {
elements = [elements];
}
for (; i < elements.length; i++) {
// If jQuery is supported
if ($) {
$(elements[i]).on(event, callback);
// Default way to support events
} else if ('addEventListener' in elements[i]) {
elements[i].addEventListener(event, callback, false);
}
}
},
/*
* Convenience function to trigger event
* @param event {string} event type
* @param modal {string} id of modal that the event is triggered on
*/
trigger: function (event, modal) {
var eventTrigger;
var eventParams = {
detail: {
'modal': modal
}
};
// Use jQuery to fire the event if it is included
if ($) {
$(document).trigger(event, eventParams);
// Use createEvent if supported (that's mostly the case)
} else if (document.createEvent) {
eventTrigger = document.createEvent('CustomEvent');
eventTrigger.initCustomEvent(event, false, false, {
'modal': modal
});
document.dispatchEvent(eventTrigger);
// Use CustomEvents if supported
} else {
eventTrigger = new CustomEvent(event, eventParams);
document.dispatchEvent(eventTrigger);
}
},
/*
* Convenience function to add a class to an element
* @param element {Node} element to add class to
* @param className {string}
*/
addClass: function (element, className) {
if (element && !element.className.match(className)) {
element.className += ' ' + className;
}
},
/*
* Convenience function to remove a class from an element
* @param element {Node} element to remove class off
* @param className {string}
*/
removeClass: function (element, className) {
element.className = element.className.replace(className, '').replace(' ', ' ');
},
/**
* Convenience function to check if an element has a class
* @param {Node} element Element to check classname on
* @param {string} className Class name to check for
* @return {Boolean} true, if class is available on modal
*/
hasClass: function (element, className) {
return !!element.className.match(className);
},
/*
* Focus modal
*/
setFocus: function () {
if (modal.activeElement) {
// Set element with last focus
modal.lastActive = document.activeElement;
// New focussing
modal.activeElement.focus();
// Add handler to keep the focus
modal.keepFocus(modal.activeElement);
}
},
/*
* Unfocus
*/
removeFocus: function () {
if (modal.lastActive) {
modal.lastActive.focus();
}
},
/*
* Keep focus inside the modal
* @param element {node} element to keep focus in
*/
keepFocus: function (element) {
var allTabbableElements = [];
// Don't keep the focus if the browser is unable to support
// CSS3 selectors
try {
allTabbableElements = element.querySelectorAll(modal.tabbableElements);
} catch (ex) {
return;
}
var firstTabbableElement = modal.getFirstElementVisible(allTabbableElements);
var lastTabbableElement = modal.getLastElementVisible(allTabbableElements);
var focusHandler = function (event) {
var keyCode = event.which || event.keyCode;
// TAB pressed
if (keyCode !== 9) {
return;
}
// Polyfill to prevent the default behavior of events
event.preventDefault = event.preventDefault || function () {
event.returnValue = false;
};
// Move focus to first element that can be tabbed if Shift isn't used
if (event.target === lastTabbableElement && !event.shiftKey) {
event.preventDefault();
firstTabbableElement.focus();
// Move focus to last element that can be tabbed if Shift is used
} else if (event.target === firstTabbableElement && event.shiftKey) {
event.preventDefault();
lastTabbableElement.focus();
}
};
modal.on('keydown', element, focusHandler);
},
/*
* Return the first visible element of a nodeList
*
* @param nodeList The nodelist to parse
* @return {Node|null} Returns a specific node or null if no element found
*/
getFirstElementVisible: function (nodeList) {
var nodeListLength = nodeList.length;
// If the first item is not visible
if (!modal.isElementVisible(nodeList[0])) {
for (var i = 1; i < nodeListLength - 1; i++) {
// Iterate elements in the NodeList, return the first visible
if (modal.isElementVisible(nodeList[i])) {
return nodeList[i];
}
}
} else {
return nodeList[0];
}
return null;
},
/*
* Return the last visible element of a nodeList
*
* @param nodeList The nodelist to parse
* @return {Node|null} Returns a specific node or null if no element found
*/
getLastElementVisible: function (nodeList) {
var nodeListLength = nodeList.length;
var lastTabbableElement = nodeList[nodeListLength - 1];
// If the last item is not visible
if (!modal.isElementVisible(lastTabbableElement)) {
for (var i = nodeListLength - 1; i >= 0; i--) {
// Iterate elements in the NodeList, return the first visible
if (modal.isElementVisible(nodeList[i])) {
return nodeList[i];
}
}
} else {
return lastTabbableElement;
}
return null;
},
/*
* Convenience function to check if an element is visible
*
* Test idea taken from jQuery 1.3.2 source code
*
* @param element {Node} element to test
* @return {boolean} is the element visible or not
*/
isElementVisible: function (element) {
return !(element.offsetWidth === 0 && element.offsetHeight === 0);
},
/*
* Mark modal as active
* @param element {Node} element to set active
*/
setActive: function (element) {
modal.addClass(element, 'is-active');
modal.activeElement = element;
// Update aria-hidden
modal.activeElement.setAttribute('aria-hidden', 'false');
// Set the focus to the modal
modal.setFocus(element.id);
// Fire an event
modal.trigger('cssmodal:show', modal.activeElement);
},
/*
* Unset previous active modal
* @param isStacked {boolean} `true` if element is stacked above another
* @param shouldNotBeStacked {boolean} `true` if next element should be stacked
*/
unsetActive: function (isStacked, shouldNotBeStacked) {
modal.removeClass(document.documentElement, 'has-overlay');
if (modal.activeElement) {
modal.removeClass(modal.activeElement, 'is-active');
// Fire an event
modal.trigger('cssmodal:hide', modal.activeElement);
// Update aria-hidden
modal.activeElement.setAttribute('aria-hidden', 'true');
// Unfocus
modal.removeFocus();
// Make modal stacked if needed
if (isStacked && !shouldNotBeStacked) {
modal.stackModal(modal.activeElement);
}
// If there are any stacked elements
if (!isStacked && modal.stackedElements.length > 0) {
modal.unstackModal();
}
// Reset active element
modal.activeElement = null;
}
},
/*
* Stackable modal
* @param stackableModal {node} element to be stacked
*/
stackModal: function (stackableModal) {
modal.addClass(stackableModal, 'is-stacked');
// Set modal as stacked
modal.stackedElements.push(modal.activeElement);
},
/*
* Reactivate stacked modal
*/
unstackModal: function () {
var stackedCount = modal.stackedElements.length;
var lastStacked = modal.stackedElements[stackedCount - 1];
modal.removeClass(lastStacked, 'is-stacked');
// Set hash to modal, activates the modal automatically
global.location.hash = lastStacked.id;
// Remove modal from stackedElements array
modal.stackedElements.splice(stackedCount - 1, 1);
},
/*
* When displaying modal, prevent background from scrolling
* @param {Object} event The incoming hashChange event
* @return {void}
*/
mainHandler: function (event, noHash) {
var hash = global.location.hash.replace('#', '');
var index = 0;
var tmp = [];
var modalElement;
var modalChild;
// JS-only: no hash present
if (noHash) {
hash = event.currentTarget.getAttribute('href').replace('#', '');
}
modalElement = document.getElementById(hash);
// Check if the hash contains an index
if (hash.indexOf('/') !== -1) {
tmp = hash.split('/');
index = tmp.pop();
hash = tmp.join('/');
// Remove the index from the hash...
modalElement = document.getElementById(hash);
// ... and store the index as a number on the element to
// make it accessible for plugins
if (!modalElement) {
throw new Error('ReferenceError: element "' + hash + '" does not exist!');
}
modalElement.index = (1 * index);
}
// If the hash element exists
if (modalElement) {
// Polyfill to prevent the default behavior of events
try {
event.preventDefault();
} catch (ex) {
event.returnValue = false;
}
// Get first element in selected element
modalChild = modalElement.children[0];
// When we deal with a modal and body-class `has-overlay` is not set
if (modalChild && modalChild.className.match(/modal-inner/)) {
// Make previous element stackable if it is not the same modal
modal.unsetActive(
!modal.hasClass(modalElement, 'is-active'),
(modalElement.getAttribute('data-stackable') === 'false')
);
// Set an html class to prevent scrolling
modal.addClass(document.documentElement, 'has-overlay');
// Set scroll position for modal
modal._currentScrollPositionY = global.scrollY;
modal._currentScrollPositionX = global.scrollX;
// Mark the active element
modal.setActive(modalElement);
modal.activeElement._noHash = noHash;
}
} else {
// If activeElement is already defined, delete it
modal.unsetActive();
}
return true;
},
/**
* Inject iframes
*/
injectIframes: function () {
var iframes = document.querySelectorAll('[data-iframe-src]');
var iframe;
var i = 0;
for (; i < iframes.length; i++) {
iframe = document.createElement('iframe');
iframe.src = iframes[i].getAttribute('data-iframe-src');
iframe.setAttribute('webkitallowfullscreen', true);
iframe.setAttribute('mozallowfullscreen', true);
iframe.setAttribute('allowfullscreen', true);
iframes[i].appendChild(iframe);
}
},
/**
* Listen to all relevant events
* @return {void}
*/
init: function () {
/*
* Hide overlay when ESC is pressed
*/
this.on('keyup', document, function (event) {
var hash = global.location.hash.replace('#', '');
// If key ESC is pressed
if (event.keyCode === 27) {
if (modal.activeElement && hash === modal.activeElement.id) {
global.location.hash = '!';
} else {
modal.unsetActive();
}
if (modal.lastActive) {
return false;
}
// Unfocus
modal.removeFocus();
}
}, false);
/**
* Trigger main handler on click if hash is deactivated
*/
this.on('click', document.querySelectorAll('[data-cssmodal-nohash]'), function (event) {
modal.mainHandler(event, true);
});
// And close modal without hash
this.on('click', document.querySelectorAll('.modal-close'), function (event) {
if (modal.activeElement._noHash){
modal.mainHandler(event, true);
}
});
/*
* Trigger main handler on load and hashchange
*/
this.on('hashchange', global, modal.mainHandler);
this.on('load', global, modal.mainHandler);
/**
* Prevent scrolling when modal is active
* @return {void}
*/
global.onscroll = global.onmousewheel = function () {
if (document.documentElement.className.match(/has-overlay/)) {
global.scrollTo(modal._currentScrollPositionX, modal._currentScrollPositionY);
}
};
/**
* Inject iframes
*/
modal.injectIframes();
}
};
/*
* AMD, module loader, global registration
*/
// Expose modal for loaders that implement the Node module pattern.
if (typeof module === 'object' && module && typeof module.exports === 'object') {
module.exports = modal;
// Register as an AMD module
} else if (typeof define === 'function' && define.amd) {
define('CSSModal', [], function () {
// We use jQuery if the browser doesn't support CustomEvents
if (!global.CustomEvent && !$) {
throw new Error('This browser doesn\'t support CustomEvent - please include jQuery.');
}
modal.init();
return modal;
});
// Export CSSModal into global space
} else if (typeof global === 'object' && typeof global.document === 'object') {
global.CSSModal = modal;
modal.init();
}
}(window, window.jQuery));

46
Seenginx/wwwroot/js/ui.js Normal file
View File

@ -0,0 +1,46 @@
(function (window, document) {
var layout = document.getElementById('layout'),
menu = document.getElementById('menu'),
menuLink = document.getElementById('menuLink'),
content = document.getElementById('main');
function toggleClass(element, className) {
var classes = element.className.split(/\s+/),
length = classes.length,
i = 0;
for(; i < length; i++) {
if (classes[i] === className) {
classes.splice(i, 1);
break;
}
}
// The className is not found
if (length === classes.length) {
classes.push(className);
}
element.className = classes.join(' ');
}
function toggleAll(e) {
var active = 'active';
e.preventDefault();
toggleClass(layout, active);
toggleClass(menu, active);
toggleClass(menuLink, active);
}
menuLink.onclick = function (e) {
toggleAll(e);
};
content.onclick = function(e) {
if (menu.className.indexOf('active') !== -1) {
toggleAll(e);
}
};
}(this, this.document));