zensational
Got Bash and 5 minutes? Great, you're almost there!
Prerequisites
zensational requires Bash 4. This is it!
Alternatively, you can use the provided
Docker image.
If Python is available, zensational can use
SimpleHTTPServer
for serving resources in development mode.
On Windows, you may want to install Cygwin or Git for Windows, which comes with a compatible Bash version.
Installation
- Download zensational 1.41 from Github
- Open Bash and run zen.sh setup
- Checkout the Quickstart Tutorial
A picture paints a thousand words.
Tasks
- build
- build the application
- clean
- clean the output
- dist
- create project distribution
- help
- display this help
- install
- install the dependencies
- new
- create a new project
- run
- start the web application
- setup
- download and install zensational
- template
- run template engine
- version
- output version information
Creating a new Project
$ zen.sh -d /tmp/demo/ new
Creating a new project in "/tmp/demo"
Application name (default: "app"): demo
Version (default "1.41"):
Starter (default "standard"): empty
Port (default "8080"):
Writing "/tmp/demo/Dockerfile"
Writing "/tmp/demo/zen"
Writing "/tmp/demo/zen.json"
Starting the Server
$ cd /tmp/demo/
$ zen run
:install:import "base"
:install:import "asserts"
:install:import "components"
module "components" requires "dom"
:install:import "dom"
module "components" requires "string"
:install:import "string"
module "dom" already imported
:install:import "events"
:install:import "net"
module "string" already imported
:install
:build
:run
Starting webserver at port 8080...
Sun, 01 Apr 2018 08:00:14 +0200 | INFO | server | | Serving static content from : /tmp/demo/app
Sun, 01 Apr 2018 08:00:14 +0200 | INFO | server | | Starting WebSocket server : ws://localhost:8080/
Sun, 01 Apr 2018 08:00:15 +0200 | INFO | server | | Serving CGI or static files : http://localhost:8080/
Sun, 01 Apr 2018 08:00:26 +0200 | ACCESS | http | url:'http://localhost:8080/js/zen.js' | STATIC
Building the Distribution
$ zen dist docker
:install UP-TO-DATE
:build
:dist:docker
Creating Docker image...
Docker version 18.06.1-ce, build e68fc7a
Sending build context to Docker daemon 12.8kB
Step 1/2 : FROM zensational:1.41
---> 637f8761e5fe
Step 2/2 : COPY ./ /var/www/
---> Using cache
---> 8e9dc3806dfd
Successfully built 8e9dc3806dfd
Successfully tagged demo:latest
:dist
Color in zensational is based on silky matt hues that have sharp contrast on bright and dark themes.
zensational's Color System
The primary color refers to the color that appears most frequently in your application.
Secondary colors can be used to emphasize or highlight important information.
Using colors from the Material Design palette is optional.
Secondary colors can be used to emphasize or highlight important information.
Using colors from the Material Design palette is optional.
Color Palette
The color palette comprises four base colors and four contrast colors that harmonize with each other.
This themes ensures consistent styling on different types of applications.
The spectrum can be filled by increasing and decreasing saturation.
This themes ensures consistent styling on different types of applications.
The spectrum can be filled by increasing and decreasing saturation.
Light Crimson
()
()
Amber
()
()
Lawn Green
()
()
Sea Blue
()
()
Primary
()
()
Snow White
()
()
Anthracite
()
()
Black
()
()
Legibility
Text on Bright Background
Text that appears on bright background should be legible.
The colors mustn't have too much brightness while being as colorful and clean as possible.
The colors mustn't have too much brightness while being as colorful and clean as possible.
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
Text on Colored Background
It is legit to apply the color palette to the background.
Therefore, it is important that the hues have enough contrast.
Therefore, it is important that the hues have enough contrast.
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
Text on Dark Background
Text that appears on dark background should be legible.
The right balance on saturation and brightness is mandatory in order to display silky matt text.
The right balance on saturation and brightness is mandatory in order to display silky matt text.
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
TEXT
Lato is the standard typeface. Source Sans Pro is used for emphasizing accents in headlines.
Styles
Type sizes are specified with rem (relative to font-size of the root element) to ensure consistent scaling.These sizes and styles were defined provide both a clean and lightweight appearance as well as readability.
Typeface
The following variants can be used to emphasize text:
- Light (300)
- Regular (400)
- Bold (700)
ABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz
0123456789
abcdefghijklmnopqrstuvwxyz
0123456789
ABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz
0123456789
abcdefghijklmnopqrstuvwxyz
0123456789
ABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz
0123456789
abcdefghijklmnopqrstuvwxyz
0123456789
Styles
The basic set of styles are based on a typographic scale of 12, 14, 16 and 20.
display-4
display-3
display-2
display-1
headline
title
subheading
body-2
body-1
Example
The quick brown fox jumps over a lazy dog.
How razorback jumping frogs can level six piqued gymnasts.
How quickly daft jumping zebras vex.
Pack my box with five dozen liquor jugs.
We promptly judged antique ivory buckles for the next prize.
Sixty zippers were quickly picked from the woven jute bag.
Crazy Fredrick bought many very exquisite opal jewels.
Jump by vow of quick, lazy strength in Oxford.
Sphinx of black quartz: judge my vow.
Quick zephyrs blow, vexing daft Jim.
Waltz, nymph, for quick jigs vex bud.
A card is a defined layer that contains detailed contextual information.
Layout
Basic
Cards are vertical containers consisting of header, body and footer.
The header can be colored individually and describes the context.
The body contains a detailed message or an image.
The footer may contain buttons for triggering context-specific actions.
The header can be colored individually and describes the context.
The body contains a detailed message or an image.
The footer may contain buttons for triggering context-specific actions.
Good News
Card Layout is available in zensational.
Image
Background images can be used for a more vivid design.
Nothing's there!
Nothing's there!
Nothing's there!
image in card (no body)
image in header (no body)
image in body
Card Collection
Cards are a convenient layer for displaying different elements.
For example, they can be used to display photo galleries.
For example, they can be used to display photo galleries.
Word of the Day
signanz
Signanz is a term used to add unnecessary complexity to otherwise simple statements or questions
in order to make the author and his work look more sophisticated regardless of his or its actual signanz.
Weather Forecast
Either it will be sunny or not.
3.141592653589793238462643383279502884197169399375105820974944
Data tables display rows of various data.
Layout
A data table contains a header row, which displays the column names.
Below, there is an arbitrary number of rows containing raw data.
Rows can contain checkboxes if the rows are supposed to be selectable.
Furthermore, icons and other visualizations may be used.
Below, there is an arbitrary number of rows containing raw data.
Rows can contain checkboxes if the rows are supposed to be selectable.
Furthermore, icons and other visualizations may be used.
Interaction
Hover
If a row is hovered by the user, the rows background color changes.
At most one row can be highlighted at one point in time.
At most one row can be highlighted at one point in time.
ID | Name | Min | Max | Sum |
---|---|---|---|---|
1 | Amsterdam | 0 | 100 | 100 |
2 | Berlin | 27 | 85 | 110 |
3 | Cairo | 14 | 64 | 78 |
ID | Name | Min | Max | Sum |
---|---|---|---|---|
1 | Amsterdam | 0 | 100 | 100 |
2 | Berlin | 27 | 85 | 110 |
3 | Cairo | 14 | 64 | 78 |
Selection
If a table supports row selection, selected rows are highlighted.
Selected rows permanently change their background color.
Row selection can be done either by:
Selected rows permanently change their background color.
Row selection can be done either by:
- clicking on desired row or
- selecting the designed checkbox (if provided).
ID | Name | Min | Max | Sum |
---|---|---|---|---|
1 | Amsterdam | 0 | 100 | 100 |
2 | Berlin | 27 | 85 | 110 |
3 | Cairo | 14 | 64 | 78 |
ID | Name | Min | Max | Sum |
---|---|---|---|---|
1 | Amsterdam | 0 | 100 | 100 |
2 | Berlin | 27 | 85 | 110 |
3 | Cairo | 14 | 64 | 78 |
The Grid is a layout component for different screen sizes.
Layout
A grid always has 12 columns which dynamically resize on tablet size and phone size, respectively.
Cells are laid out sequentially in a row, in the defined order.
If a cell doesn't fit in the row, it flows into the following line.
If a row contains cells which sum up to less than 12, the cells dynamically expand.
Cells are laid out sequentially in a row, in the defined order.
If a cell doesn't fit in the row, it flows into the following line.
If a row contains cells which sum up to less than 12, the cells dynamically expand.
1
11
2
10
3
9
4
8
5
7
6
6
7
5
8
4
9
3
10
2
11
1
12
0
6
5
4
Lists present multiple rectangular items vertically aligned.
Layout
For collections of ordered items with compact content, lists shall be used.
Each row contains a single cell with text and or images.
Each row contains a single cell with text and or images.
Jane Doe
jane.doe@work.com
John Doe
john.doe@abc.xyz
John Smith
john@smith.co.uk
Jane Doe
jane.doe@work.com
John Doe
john.doe@abc.xyz
John Smith
john@smith.co.uk
Selection controls allow the user to select one or more options.
Types of Selection Controls
Checkboxes
Checkboxes allow the selection of zero or more options from a given set.
Radio Buttons
Radio buttons allow the selection of exactly one option from a given set.
Text fields allow users to input, edit, and select text.
Layout
Text fields contain the following elements:Label
Labels display the name and semantics of the text field.
Every text field should have a label.
Every text field should have a label.
Placeholder
Empty input fields may contain placeholder text.
The text can contain an example, such as a phone number.
The text can contain an example, such as a phone number.
Helper Text
Additional information may be displayed below a fields.
It should be visible either persistently or only on focus.
It should be visible either persistently or only on focus.
Must contain only numbers
At least 8 characters
Error Message
Upon validation errors, text fields can display an error message below the field.
This message should contain instructions on how to fix the error.
Additionally, an icon or the term "Error" should be used to increase visibility.
The error message is displayed permanently and replaces the helper text.
This message should contain instructions on how to fix the error.
Additionally, an icon or the term "Error" should be used to increase visibility.
The error message is displayed permanently and replaces the helper text.
Error: Must contain only numbers
Passwords do not match
A template is a reusable fragment of text containing directives.
Overview
zensational has builtin directives for the following use cases:- Variables
- Strings - Basics
- Strings - Case Format
- Strings - Substring
- Strings - Replacement
- Call External Program
- Integer Arithmetic
- Conditions
- Loops
- Imports
Variables
Variable
#var CLASSES="z-text--code z-cell z-cell--5-col"
# sets CLASSES to "z-text--code z-cell z-cell--5-col"
Call other program
#var DATE="$(date +%s.%N)"
# sets DATE to "1554023497.229712651"
String Interpolation
#var path="${HOME} sweet home"
# sets path to "/home/user sweet home"
Constant
#val CSS="CLASSES"
#const CSS="OVERRIDE"
#const CSS="OVERRIDE"
# sets CSS To "CLASSES"
# component.zt.sh: line 69: CSS: readonly variable
Resolve variable by name
${!CSS}
(${CSS})
(${CSS})
z-text--code z-cell z-cell--5-col
(CLASSES)
(CLASSES)
Strings - Basics
Length
${#path}
21
Strings - Case Format
Upper Case
${CLASSES^^}
Z-TEXT--CODE Z-CELL Z-CELL--5-COL
Lower Case
${CLASSES,,}
z-text--code z-cell z-cell--5-col
Strings - Substring
Starts with index
${path:10}
sweet home
Starts with index (reverse)
${path:(-4)}
home
Substring
${path:6:4}
user
Remove prefix
${path#*/}
home/user sweet home
Remove prefix (greedy)
${path##*/}
user sweet home
Remove suffix
${path%o*}
/home/user sweet h
Remove suffix (greedy)
${path%%o*}
/h
Strings - Replacement
Replace first occurrence
${path/home/castle}
/castle/user sweet home
Replace all occurrences
${path//home/castle}
/castle/user sweet castle
Replace prefix
${path/#\/home/\/castle}
/castle/user sweet home
Replace suffix
${path/%home/castle}
/home/user sweet castle
Call External Program
Simple call
$(hostname)
zen
Call perl with arguments
$(perl -e "print 3/2.")
1.5
Execute JavaScript using Java
$(jjs -e "print 3/2.")
1.5
Integer Arithmetic
Addition
$((2+3))
5
Subtraction
$((2-3))
-1
Multiplication
$((2*3))
6
Division
$((2/3))
0
Increment
#var a=2
$((a+=1))
$((a+=1))
# sets a to 2
3
Conditions
if
#if [ 0 < 1 ]
0 < 1
#endif
0 < 1
#endif
0 < 1
if-else
#if [ 0 >= 1 || 0 <= 1 ]
tautology
#else
contradiction
#endif
tautology
#else
contradiction
#endif
tautology
if-elif
#if [ ${a} == 2 && 2 != "${a}" ]
contradiction
#elif [ "$a" == ${a} ]
a=$a
#endif
contradiction
#elif [ "$a" == ${a} ]
a=$a
#endif
a=2
Loops
Iteration
#for i in 1..3
${i}*($i+1)=$((i*($i+1)))<br>
#endfor
${i}*($i+1)=$((i*($i+1)))<br>
#endfor
1*(1+1)=2
2*(2+1)=6
3*(3+1)=12
2*(2+1)=6
3*(3+1)=12
Enumeration
<ul>
#for str in a $a "$CLASSES" $CLASSES
<li>${str}</li>
#endfor
</ul>
#for str in a $a "$CLASSES" $CLASSES
<li>${str}</li>
#endfor
</ul>
- a
- 2
- z-text--code z-cell z-cell--5-col
- z-text--code
- z-cell
- z-cell--5-col
Imports
footer.zt<div>
created at ${DATE}
<span class="z-text--highlight">$2</span>
args: $@
</div>
Import
#var NOW="$(date +%s.%N)"
#var DIFF= "$(echo print "${NOW}-${DATE}" | perl)"
#import footer "in" ${DIFF} sec
#var DIFF= "$(echo print "${NOW}-${DATE}" | perl)"
#import footer "in" ${DIFF} sec
# sets NOW to "1554023497.269611725"
# sets DIFF to "0.0398991107940674"
# sets DIFF to "0.0398991107940674"
created at 1554023497.229712651
0.0398991107940674
args: in 0.0398991107940674 sec
0.0398991107940674
args: in 0.0398991107940674 sec
zensational reduces the size of Google Search significantly.
Source Code
index.zt
<!--
Copyright 2018 The zensational authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
#const WEBSITE=Google
<!DOCTYPE html>
<html itemscope="" itemtype="http://schema.org/WebPage" lang="en-US">
#import templates/head
<body class="hp vasq zhe" id="gsr">
<div class="ctr-p" id="viewport">
<div id="doc-info"></div>
<div id="cst">
</div>
<div class="jhp big" id="searchform">
#import templates/apps Mail Images
<form class="tsf" style="overflow:visible" id="tsf" method="GET" name="f" onsubmit="alert('April Fools!');">
<div class="tsf-p">
<div class="sfibbbc">
<div class="sbtc" id="sbtc">
<div class="sbibtd">
<div class="sbibod " id="sfdiv">
<div class="lst-c">
<div class="gstl_0 sbib_a" style="height: 44px;">
<div class="gsst_b sbib_c" id="gs_st0" style="line-height: 44px;" dir="ltr">
<a class="gsst_a z-text--headline" href="#"><span class="gsri_a lnr lnr-mic" id="gsri_ok0"></span></a>
</div>
<div class="sbib_b" id="sb_ifc0" dir="ltr">
<div id="gs_lc0" style="position: relative;">
<input class="" id="lst-ib" maxlength="2048" name="q" autocomplete="off" title="Search" value=""
style="width: 100%; position: absolute; z-index: 6; left: 0; outline: none;"
dir="ltr" spellcheck="false">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="jsb" style="padding-top:18px">
<center>
#import templates/button "btnK" "Search"
#import templates/button "btnI" "I'm Feeling Happy"
</center>
</div>
</div>
</form>
</div>
<div class="sfbgx"></div>
<div id="gac_scont"></div>
<div class="content" id="main"><span class="ctr-p z-text--center" id="body">
<div style="height:233px;margin-top:89px" id="lga">
#import templates/logo "${WEBSITE}" "BRYBGR"
</div>
<div style="height:118px"></div>
<div id="prm-pt" style="margin-top:12px">
<div id="als"><div id="CToSde">Search offered in: <a class="z-link" href="#">English</a> </div></div>
<div id="swml"></div>
</div>
</span>
#import templates/footer
</div>
</div>
<link rel="stylesheet" href="css/style.css">
</body>
</html>
templates/head.zt
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link href="https://cdn.linearicons.com/free/1.0.0/icon-font.min.css" rel="stylesheet">
<meta content="origin" name="referrer">
<title>Search</title>
<link rel="stylesheet" href="css/misc.css">
</head>
templates/apps.zt
#var apps="$@"
<div id="gb" class="gb_T">
<div id="gbw">
<div style="top:0;left:0;right:0;width:100%">
<div class="gb_nb gb_Lg gb_R gb_Kg gb_Og gb_T" style="min-width: 220px;">
<div class="gb_oe gb_R gb_Lg gb_Bg">
#for app in ${apps}
<div class="gb_Q gb_R"><a class="gb_P" href="#">${app}</a></div>
#endfor
</div>
<div class="gb_Ec gb_Lg gb_R" style="min-width: 114px;">
<div class="gb_fa" id="gbsfw" style="background-color:#eee;min-width:376px"></div>
<div class="gb_da gb_9c gb_R" id="gbwa">
<div class="gb_Qc"><a class="gb_b" href="#" title="Apps" tabindex="0">
<span class="lnr lnr-menu"></span>
</a></div>
</div>
<div class="gb_vg gb_R">
<div class="gb_Qc"><a class="z-link" id="gb_70" href="#" target="_top">Sign in</a></div>
</div>
</div>
</div>
</div>
</div>
</div>
templates/logo.zt
#var word="$1"
#var colors="$2"
#var R="red"
#var Y="yellow"
#var G="green"
#var B="blue"
#for (( i=0; i<${#word}; i++ ))
#var char="${word:$i:1}"
#var color_code="${colors:$i:1}"
<span class="z-color-text--${!color_code}">${char}</span>
#endfor
Google Plus community discovery built using zensational.
Source Code
index.zt
<!--
Copyright 2019 The zensational authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta content="origin" name="referrer">
<base href=".">
<title>G++ - Discover</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="css/plus.css">
<link rel="stylesheet" href="../../css/zensational.min.css">
<style rel="stylesheet" type="text/css">
.z-button {
font-weight: normal;
text-decoration: none !important;
}
.z-grid {
justify-content: start !important;
}
.z--visible {
display: unset;
opacity: 1 !important;
}
.Cri5O {
bottom: 16px;
height: 70px;
}
</style>
<body id="yDmH0d" class="ghyPEc IqBfM ecJEib EWZcud cjGgHb LcUz9d" style="bottom: auto; right: auto; width: auto; height: 100%; min-height: 868px;">
<div class="SSPGKf Jvazdb">
<div class="OFyC1e">
<div class="u5oEgd">
<div class="UVZlkc">
<div class="YKZUAc eejsDc WH2D3d">
<div class="L1NA8d">
<div class="X4xgyd">
<a class="n9qFx" href="#discover">
<div class="OpEhZb"><span class="DPvwYc DCYkOe"></span></div>
<div class="kiH7Kc">Discover</div>
</a>
<a class="n9qFx" href="https://github.com/abc-inc/zensational">
<div class="OpEhZb">G++</div>
<div class="kiH7Kc">Join Community</div>
</a>
</div>
<a class="n9qFx iVNuqf" href="https://github.com/abc-inc/zensational/issues">
<div class="kiH7Kc">Send feedback</div>
</a>
<a class="n9qFx iVNuqf" href="../../zensational.html#examples_google-plus">
<div class="kiH7Kc">Help</div>
</a>
</div>
<div class="AlZIPe">© April 1, 2019 ABC Inc.<br>
· <a href="#privacy" class="mfqKsb">Privacy Policy</a><br>
· <a href="#tos" class="mfqKsb">Terms of Service</a>
</div>
</div>
</div>
</div>
</div>
<div class="AOq4tb Wxeofe">
<div class="rDQqN">
<div class="XS1fT vfJjge XS1fT___i12 RqpFEd">
<div class="FGhx7c">
<div class="Vrm0oe">
<div class="o614gf dMPbYe">
<div class="tmTbod">
<a class="xdjHt ex5ZEb kTeh9">G++</a>
</div>
</div>
<div class="f81Q3b aUhlxd">
<div class="EPPZeb"><span class="DPvwYc yuvn1"></span>
<div class="L6J0Pc VOEIyf IaFzsc">
<div class="d1dlne" style="position: relative">
<input id="search" class="yNVtPc ZAGvjd Ny5lGc" placeholder="Search G++">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="SNFoGf uYojab"></div>
</div>
<div class="T4LgNb O1bNWe">
<div class="DAbEod">
<div class="pWgqe"></div>
<div class="M7vp2c">
<div class="jx5iDb aPExg">
<div id="ebda1a" class="z-grid H68wj t1KkGe"></div>
<div id="d277db" class="z--hide"></div>
</div>
<div class="UC0Lbf kIYuLd">
<div class="EIkL5b">
<div class="Jb45He D7Ikwd"></div>
<div class="Jb45He SrWDEb"></div>
<div id="loadError" class="Jb45He w5rj0e">
<div>Unable to load more. <span class="E3qfYc">Retry</span></div>
</div>
</div>
<div id="loadStatus" class="Jb45He x5PLcf">Wait while more content is being loaded</div>
</div>
</div>
</div>
</div>
</div>
<script type="application/javascript" src="../../../js/zen.min.js"></script>
<script type="application/javascript" src="js/plus.js"></script>
js/plus.js
/*
* Copyright 2019 The zensational authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
z.require('dom');
z.require('net');
var topics_ = [];
var lastCount_ = 0;
var lastSearch_ = null;
var searchInput_ = z.dom.getElementById('search');
var searchResult_ = z.dom.getElementById('ebda1a');
var reloadButton_ = z.dom.getElementByClass('E3qfYc');
/**
* @param {number} index
* @returns {string}
*/
var getCard = function (index) {
var topic = topics_[index];
if (!z.isDefAndNotNull(topic.dom)) {
topic.dom = renderCard_(index, topic['id'], topic['title'], topic['color'], topic['image']);
}
return topic.dom;
};
/**
* @param {number} index
* @param {string} id
* @param {string} title
* @param {string} color
* @param {string} image
* @returns {string}
*/
var renderCard_ = function (index, id, title, color, image) {
return '' +
'<div id="topic_' + id + '" class="z-cell z-cell--3-col NzRmxf vCjazd">' +
'<h2 class="SDJOje"></h2>' +
'<a class="w2Aa4 wRd1We kUqoPd" style="' + color + '" href="">' +
'<div>' +
'<div class="E68jgf" style="padding-top: 56.25%"><img class="JZUAbb" src="images/' + image + '" height="180" width="320" alt=""></div>' +
'</div>' +
'<div class="Cri5O"><div class="t8kvre">' + title + '</div>' +
'<div class="nerE3c"><div class="UUUH4c"><div class="U26fgb O0WRkf oG5Srb C0oVfc B7Nypc aKZ15">' +
'<div class="Vwe4Vb MbhUzd"></div>' +
'<div class="ZFr60d CeoRYc"></div>' +
'<content class="CwaK9"><span class="RveJvd snByac"><div class="Yak35d">Follow</div></span></content>' +
'</div></div></div>' +
'</div>' +
'</a>' +
'</div>';
};
/**
* @param {number} number
*/
var addCards = function (number) {
var value = searchInput_.value.toLowerCase();
for (var i = 0, added = 0; i < topics_.length && added < number; i++) {
var topic = topics_[i];
var matches = topic['title'].toLowerCase().indexOf(value);
if (matches >= 0 && !z.isDefAndNotNull(z.dom.getElementById('topic_' + topic['id']))) {
z.dom.appendNode(searchResult_, getCard(i));
lastCount_++;
added++;
}
}
var visClass = 'z--visible';
var loadStatus = z.dom.getElementById('loadStatus');
var loadError = z.dom.getElementById('loadError');
loadStatus.classList.remove(visClass);
loadError.classList.remove(visClass);
if (lastCount_ < 5) {
loadStatus.classList.add(visClass);
if (!z.isDefAndNotNull(lastSearch_)) {
lastSearch_ = new Date();
setTimeout(function () {
lastSearch_ = null;
loadStatus.classList.remove(visClass);
if (lastCount_ < 5) {
loadStatus.classList.remove(visClass);
loadError.classList.add(visClass)
}
}, 5000);
}
} else {
loadStatus.classList.remove(visClass);
}
};
/**
* @returns {number}
*/
var getPageScrollOffset = function () {
var yScroll;
if (window.pageYOffset) {
yScroll = window.pageYOffset;
} else if (document.documentElement && document.documentElement.scrollTop) {
yScroll = document.documentElement.scrollTop;
} else if (document.body) {
yScroll = document.body.scrollTop;
}
return yScroll;
};
z.net.get('topics.json', function (response) {
topics_ = JSON.parse(response.target.responseText);
var searchResult = z.dom.getElementById('ebda1a');
while (searchResult.childElementCount < Math.min(30, topics_.length)) {
var number = Math.floor(Math.random() * topics_.length);
if (!z.isDefAndNotNull(topics_[number].dom)) {
z.dom.appendNode(searchResult, getCard(number));
}
}
});
document.addEventListener('scroll', function (e) {
var offset = getPageScrollOffset();
var height = Math.max(document.documentElement.clientHeight, window.innerHeight || 256);
var bodyHeight = Math.max(document.body.scrollHeight, document.body.offsetHeight,
document.documentElement.clientHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight);
if (offset + height + 200 > bodyHeight) {
addCards(20);
}
});
searchInput_.addEventListener('keyup', function (e) {
z.dom.removeChildren(searchResult_);
lastCount_ = 0;
addCards(30);
});
reloadButton_.addEventListener('click', function (e) {
location.reload(true);
});