web documentation templates and resources

This commit is contained in:
Ivan Smolin 2017-06-23 19:15:43 +03:00
parent c0b101d1ff
commit dfecd2cdc4
28 changed files with 1852 additions and 0 deletions

View File

@ -0,0 +1,20 @@
{%- import '../utils.twig' as utils -%}
<div class="row-body">
<div>{{ field.jsonName }}</div>
<div>
{%- set link = null -%}
{%- for name, path in objectsLinks -%}
{%- if name == field.type.type.baseTypeName -%}
{%- set link = path -%}
{%- endif -%}
{%- endfor -%}
{%- if link is not null -%}
<a class="info" href="{{ link }}">{{- utils.formatNullable(field.type.type.typeName, field.nullable) -}}</a>
{% else %}
{{- utils.formatNullable(field.type.type.typeName, field.nullable) -}}
{%- endif -%}
</div>
<div>{{ field.description }}</div>
<div>{{ utils.optionalDescription(field.optional) }}</div>
</div>

View File

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ title }}</title>
<link type="text/css" rel="stylesheet" href="{{ cssFolderPath }}/main.css?v=1.07" media="all">
<link type="text/css" rel="stylesheet" href="{{ cssFolderPath }}/fonts.css?v=1.07" media="all">
<link type="text/css" rel="stylesheet" href="{{ cssFolderPath }}/normalize.css" media="all">
</head>

View File

@ -0,0 +1,11 @@
<div class="header">
<div class="search-block">
<i class="icon-search"></i>
<input type="text" placeholder="Поиск">
<div class="typeahead-container typeahead-container--hide"><div class="typeahead-content"></div></div>
</div>
<div class="logo">
<img src="{{ imagesFolderPath }}/logo.png">
</div>
</div>

View File

@ -0,0 +1,8 @@
<menu class="main">
<li {%- if mainMenu.indexMenuItem.active %} class="active" {%- endif -%}><a href="{{ mainMenu.indexMenuItem.path }}">Общие принципы построения API</a></li>
<li {%- if mainMenu.methodsMenuItem.active %} class="active" {%- endif -%}><a href="{{ mainMenu.methodsMenuItem.path }}">Методы</a></li>
<li {%- if mainMenu.notificationsMenuItem.active %} class="active" {%- endif -%}><a href="{{ mainMenu.notificationsMenuItem.path }}">PUSH-нотификации</a></li>
<li {%- if mainMenu.structuresMenuItem.active %} class="active" {%- endif -%}><a href="{{ mainMenu.structuresMenuItem.path }}">Структура данных</a></li>
<li {%- if mainMenu.versioningMenuItem.active %} class="active" {%- endif -%}><a href="{{ mainMenu.versioningMenuItem.path }}">Версионнирование API</a></li>
<li {%- if mainMenu.errorsMenuItem.active %} class="active" {%- endif -%}><a href="{{ mainMenu.errorsMenuItem.path }}">Список возможных ошибок</a></li>
</menu>

View File

@ -0,0 +1,2 @@
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<script type="text/javascript" src="{{ jsFolderPath }}/main.js?v=1.02"></script>

View File

@ -0,0 +1,8 @@
<li {%- if menu.active %} class="active" {%- endif -%}>
<a href="{{ first(menu.items).path }}">{{ menuTitle }}</a>
<menu class="child">
{% for item in menu.items %}
<li {%- if item.active %} class="active" {%- endif -%}><a href="{{ item.path }}">{{ item.title }}</a></li>
{% endfor %}
</menu>
</li>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,500 @@
*,:after,:before {
box-sizing: border-box
}
html {
font-size: 10px;
}
.text-centered {
text-align: center;
}
body {
background-color: #222933;
font-size: 0;
line-height: 0;
min-width: 128rem;
font-family: 'SanFrancisco', sans-serif;
}
.aside {
display: inline-block;
vertical-align: top;
font-size: 14px;
}
.header {
height: 7rem;
font-size: 14px;
}
.content {
min-height: calc(100vh - 7rem);
font-size: 14px;
line-height: 1rem;
}
.aside-left {
width: 38.85rem;
}
.aside-left .header {
background-color: #333c48;
border-right: 1px solid #323b46;
border-bottom: 1px solid #2b333e;
}
.logo img {
height: 3.6em;
margin: .7em 0 0 2em;
}
.search-block {
float: right;
margin: 1.85rem 1.28rem 0 0;
font-size: 1.28rem;
padding: 0 1.07rem;
border-radius: 1.71rem;
border: 1px solid #E4E6EA;
background: #F0F2F5;
color: #8D9299;
position: relative;
}
.search-block input[type="text"] {
width: 21.5rem;
height: 3.14rem;
border: 0;
background: transparent;
padding-left: 0.71rem;
color: #666;
font-size: 1.42rem;
}
.search-block input[type="text"]::-webkit-input-placeholder {
color: #777;
}
.search-block input[type="text"]:focus {
outline: none;
}
.typeahead-container {
position: absolute;
width: 100%;
background-color: white;
padding: 1.3rem .6rem 1.3rem 1.3rem;
box-shadow: 0 0 4px 1px #ccc;
left: 0;
top: 3.8rem;
}
.typeahead-container--hide {
display: none;
}
.typeahead-container:hover {
display: block;
}
.typeahead-content {
width: 100%;
max-height: 22rem;
overflow: auto;
}
.typeahead-container a:hover {
text-decoration: underline;
}
.typeahead-container a {
display: block;
line-height: 2.8rem;
font-size: 1.5rem;
color: #0ca9e6;
text-decoration: blink;
width: 85%;
overflow: hidden;
text-overflow: ellipsis;
}
.typeahead-content::-webkit-scrollbar {
width: 0.6rem;
}
.typeahead-content::-webkit-scrollbar-track {
margin-right: 10px;
padding-right: 10px;
}
.typeahead-content::-webkit-scrollbar-thumb {
background-color: #d5d6d8;
border-radius: 0.3rem;
}
.aside-left .content {
background-color: #222933;
border-right: 1px solid #888d94;
}
menu li {
cursor: pointer;
}
.aside-left menu.main {
list-style: none;
margin: 0;
background: #2b333e;
padding: 0 0 2.2rem;
}
.aside-left menu.main li a {
display: block;
line-height: 4rem;
vertical-align: middle;
padding-left: 3.57rem;
padding-right: 1.42rem;
font-size: 1.57rem;
color: #BEBFC1;
text-decoration: none;
transition: line-height .3s ease-out 0s;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.aside-left menu.main > li a:hover,
.aside-left menu.main > li.active a {
line-height: 5.28rem;
background-color: #222933;
padding-left: 3.14rem;
border-left: 6px solid #0ca9e6;
color: white
}
.aside-left menu.main > li:first-child + li.active {
margin-top: 0;
}
.aside-left menu.secondary {
list-style: none;
margin: 0;
padding: 3.57rem 0 0 6.28rem;
}
.aside-left menu.secondary li a {
line-height: 2.64rem;
vertical-align: middle;
font-size: 1.42rem;
color: #0ca9e6;
text-decoration: none;
transition: line-height .3s ease-out 0s;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
padding-right: 1.42rem;
display: inline-block;
width: 100%;
}
.aside-left menu.secondary > li:not(.active) > a:hover {
opacity: 0.8;
}
.aside-left menu.secondary > li.active > a {
color: white
}
.aside-left menu.secondary > li.active menu.child {
display: block;
}
.aside-left menu.child {
display: none;
list-style: none;
margin: 6px 0;
padding-left: 1.57rem;
border-left: 1px solid #fff;
width: 205px;
}
.aside-left menu.child > li > a{
color: #7a7f85;
}
.aside-left menu.child > li.active > a{
color: #fff;
}
.aside-right {
width: calc(100% - 38.85rem);
background-color: #f0f2f5;
}
.aside-right .header {
background-color: white;
box-shadow: 2px 1px 3px 0 #e9ebee;
width: calc(100% - 1.07rem);
border-bottom: 1px solid #e1e3e4;
}
.title {
font-size: 2rem;
line-height: 2.4rem;
padding-top: 2.2rem;
color: white;
padding-left: 4rem;
font-weight: bold;
}
.aside-right .content {
padding: 1rem;
}
.page-data {
width: 100%;
background-color: white;
min-height: calc(100vh - 9rem);
border: 1px solid #e9ebee;
padding: 5.28rem 14rem 5.28rem 6.14rem;
}
.page-data h2 {
font-size: 2rem;
margin: 4.28rem 0 1rem;
line-height: 2rem;
font-weight: 500;
}
.page-data h2:first-child {
margin-top: 0;
}
.page-data p {
font-size: 1.57rem;
color: #838890;
line-height: 2.2rem;
margin: 0.85rem 0 0;
}
.page-data a.info {
color: #0ca9e6;
cursor: pointer;
text-decoration: none;
}
.page-data a.info:hover {
text-decoration: underline;
}
.page-data p.sub-header {
font-weight: 500;
}
.table--small.table {
width: 50%;
min-width: 350px;
}
.table:first-child { margin-top: 0}
.table {
width: 100%;
border: 1px solid #c8cdd6;
border-radius: 0.71rem 0.71rem 0 0;
background-color: #e9edf3;
margin-top: 1.71rem;
}
.table > .part-table {
display: table;
width: 100%;
}
.table p {
font-size: 1.4rem;
margin: 0;
line-height: 2rem;
}
.row-header {
display: table-row;
}
.row-header > * {
display: table-cell;
font-size: 1.15rem;
text-transform: uppercase;
color: #838890;
padding: 1rem 1.42rem 1rem;
border-bottom: 1px solid #c8cdd6;
border-right: 1px solid #c8cdd6;
line-height: 1.8rem;
white-space: nowrap;
}
.row-header > *:last-child {
border-right: 0;
}
.row-body {
display: table-row;
background-color: white;
}
.row-body > * {
display: table-cell;
font-size: 1.4rem;
color: #838890;
line-height: 1.2em;
padding: 1rem;
border-bottom: 1px solid #c8cdd6;
border-right: 1px solid #c8cdd6;
}
.row-body:last-child > * {
border-bottom: 0;
}
.row-body > *:last-child {
border-right: 0;
}
.part-block {
display: block;
font-size: 1.57rem;
padding: 1.42rem 1.42rem 1.28rem;
background-color: white;
border-radius: 0 0 0.71rem 0.71rem;
border-top: 1px solid #c8cdd6;
}
.example-response-expanded .part-block {
border-radius: 0;
border-bottom: 1px solid #c8cdd6;
}
.part-example-response {
display: none;
padding: 1.42rem 1.42rem 1.28rem;
}
.example-response-expanded .part-example-response {
display: block;
}
.text-response {
padding: 1.42rem;
background-color: white;
border: 1px solid #c8cdd6;
margin: 0;
font-size: 1.2rem;
line-height: 1.57rem;
white-space: pre;
font-family: monospace;
min-height: 140px;
}
.example-response-expanded a.show-example-response:after {
transform: rotate(225deg);
top: 3px;
}
.example-response {
padding: 1.4rem;
background-color: #e9edf3;
border: 1px solid #c8cdd6;
margin-top: 10px;
}
.example-response > .text-response {
display: block;
}
.part-example-response > .inputs {
display: inline-block;
width: 14.15rem;
vertical-align: top;
margin-right: 1.42rem;
}
.part-example-response .inputs label {
display: block;
font-size: 1.28rem;
margin-top: 0.64rem;
line-height: 1.28rem;
}
.part-example-response .inputs label input {
width: 100%;
padding: 0.85rem 0.85rem 0.78rem;
margin-top: 0.35rem;
border: 1px solid #c8cdd6;
color: #838890;
height: 3.28rem;
}
.part-example-response .inputs label input::-ms-clear {
display: none;
}
.part-example-response .inputs label:first-child {
margin-top: 0.57rem;
}
.styled-select {
width: 100%;
margin-top: 0.35rem;
border: 1px solid #c8cdd6;
background: white;
overflow: hidden;
position: relative;
}
.styled-select:after {
content: '';
display: block;
position: absolute;
top: 1.07rem;
right: 1.07rem;
border: 0.35rem solid #838890;
border-bottom-color: transparent;
border-right-color: transparent;
transform: rotate(225deg);
}
.styled-select select {
position: relative;
z-index: 2;
width: 100%;
height: 100%;
padding: 0.85rem;
border: 0;
color: #838890;
background: transparent;
-ms-appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none !important;
}
.styled-select select::-ms-expand {
display: none;
}
.styled-input {
position: relative;
}
.clear-btn {
position: absolute;
right: 0;
bottom: 0;
border: 1px solid #c9ccd3;
color: #c9ccd3;
background-color: #f7faff;
width: 3.14rem;
text-align: center;
height: 1.71rem;
font-size: 2.14rem;
line-height: 1.15rem;
}
.null-btn {
position: absolute;
right: 0;
bottom: 1.64rem;
border: 1px solid #c9ccd3;
color: #c9ccd3;
background-color: #f7faff;
width: 3.14rem;
text-align: center;
height: 1.64rem;
font-size: 1rem;
line-height: 1.57rem;
}
.clear-btn:hover, .null-btn:hover {
color: #999;
cursor: pointer;
}
.disabled {
pointer-events: none;
color: #bdc0c5;
}
.disabled input{
pointer-events: all;
background-color: #f4f6f9;
}
.btn {
background-color: #0ca9e6;
border: 0;
color: white;
font-size: 1.42rem;
padding: 1.15rem;
width: 100%;
margin-top: 1.71rem;
font-weight: 500;
}
.part-example-response > .text-response {
display: inline-block;
width: calc(100% - 16rem);
vertical-align: top;
margin-top: 2.2rem;
overflow: auto;
}
span.text-digit {
color: #0060ff;
}
span.text-string {
color: #037400;
}
a.show-example-response {
color: #0275eb;
cursor: pointer;
}
a.show-example-response:after {
content: '';
border: 0.42rem solid;
position: relative;
display: inline-block;
border-top-color: transparent;
border-left-color: transparent;
transform: rotate(45deg);
margin-left: 0.71em;
top: -.28em;
}

424
Web-documentation/css/normalize.css vendored Normal file
View File

@ -0,0 +1,424 @@
/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
/**
* 1. Set default font family to sans-serif.
* 2. Prevent iOS and IE text size adjust after device orientation change,
* without disabling user zoom.
*/
html {
font-family: sans-serif; /* 1 */
-ms-text-size-adjust: 100%; /* 2 */
-webkit-text-size-adjust: 100%; /* 2 */
}
/**
* Remove default margin.
*/
body {
margin: 0;
}
/* HTML5 display definitions
========================================================================== */
/**
* Correct `block` display not defined for any HTML5 element in IE 8/9.
* Correct `block` display not defined for `details` or `summary` in IE 10/11
* and Firefox.
* Correct `block` display not defined for `main` in IE 11.
*/
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
main,
menu,
nav,
section,
summary {
display: block;
}
/**
* 1. Correct `inline-block` display not defined in IE 8/9.
* 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
*/
audio,
canvas,
progress,
video {
display: inline-block; /* 1 */
vertical-align: baseline; /* 2 */
}
/**
* Prevent modern browsers from displaying `audio` without controls.
* Remove excess height in iOS 5 devices.
*/
audio:not([controls]) {
display: none;
height: 0;
}
/**
* Address `[hidden]` styling not present in IE 8/9/10.
* Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.
*/
[hidden],
template {
display: none;
}
/* Links
========================================================================== */
/**
* Remove the gray background color from active links in IE 10.
*/
a {
background-color: transparent;
}
/**
* Improve readability of focused elements when they are also in an
* active/hover state.
*/
a:active,
a:hover {
outline: 0;
}
/* Text-level semantics
========================================================================== */
/**
* Address styling not present in IE 8/9/10/11, Safari, and Chrome.
*/
abbr[title] {
border-bottom: 1px dotted;
}
/**
* Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
*/
b,
strong {
font-weight: bold;
}
/**
* Address styling not present in Safari and Chrome.
*/
dfn {
font-style: italic;
}
/**
* Address variable `h1` font-size and margin within `section` and `article`
* contexts in Firefox 4+, Safari, and Chrome.
*/
h1 {
font-size: 2em;
margin: 0.67em 0;
}
/**
* Address styling not present in IE 8/9.
*/
mark {
background: #ff0;
color: #000;
}
/**
* Address inconsistent and variable font size in all browsers.
*/
small {
font-size: 80%;
}
/**
* Prevent `sub` and `sup` affecting `line-height` in all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sup {
top: -0.5em;
}
sub {
bottom: -0.25em;
}
/* Embedded content
========================================================================== */
/**
* Remove border when inside `a` element in IE 8/9/10.
*/
img {
border: 0;
}
/**
* Correct overflow not hidden in IE 9/10/11.
*/
svg:not(:root) {
overflow: hidden;
}
/* Grouping content
========================================================================== */
/**
* Address margin not present in IE 8/9 and Safari.
*/
figure {
margin: 1em 40px;
}
/**
* Address differences between Firefox and other browsers.
*/
hr {
box-sizing: content-box;
height: 0;
}
/**
* Contain overflow in all browsers.
*/
pre {
overflow: auto;
}
/**
* Address odd `em`-unit font size rendering in all browsers.
*/
code,
kbd,
pre,
samp {
font-family: monospace, monospace;
font-size: 1em;
}
/* Forms
========================================================================== */
/**
* Known limitation: by default, Chrome and Safari on OS X allow very limited
* styling of `select`, unless a `border` property is set.
*/
/**
* 1. Correct color not being inherited.
* Known issue: affects color of disabled elements.
* 2. Correct font properties not being inherited.
* 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
*/
button,
input,
optgroup,
select,
textarea {
color: inherit; /* 1 */
font: inherit; /* 2 */
margin: 0; /* 3 */
}
/**
* Address `overflow` set to `hidden` in IE 8/9/10/11.
*/
button {
overflow: visible;
}
/**
* Address inconsistent `text-transform` inheritance for `button` and `select`.
* All other form control elements do not inherit `text-transform` values.
* Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
* Correct `select` style inheritance in Firefox.
*/
button,
select {
text-transform: none;
}
/**
* 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
* and `video` controls.
* 2. Correct inability to style clickable `input` types in iOS.
* 3. Improve usability and consistency of cursor style between image-type
* `input` and others.
*/
button,
html input[type="button"], /* 1 */
input[type="reset"],
input[type="submit"] {
-webkit-appearance: button; /* 2 */
cursor: pointer; /* 3 */
}
/**
* Re-set default cursor for disabled elements.
*/
button[disabled],
html input[disabled] {
cursor: default;
}
/**
* Remove inner padding and border in Firefox 4+.
*/
button::-moz-focus-inner,
input::-moz-focus-inner {
border: 0;
padding: 0;
}
/**
* Address Firefox 4+ setting `line-height` on `input` using `!important` in
* the UA stylesheet.
*/
input {
line-height: normal;
}
/**
* It's recommended that you don't attempt to style these elements.
* Firefox's implementation doesn't respect box-sizing, padding, or width.
*
* 1. Address box sizing set to `content-box` in IE 8/9/10.
* 2. Remove excess padding in IE 8/9/10.
*/
input[type="checkbox"],
input[type="radio"] {
box-sizing: border-box; /* 1 */
padding: 0; /* 2 */
}
/**
* Fix the cursor style for Chrome's increment/decrement buttons. For certain
* `font-size` values of the `input`, it causes the cursor style of the
* decrement button to change from `default` to `text`.
*/
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
height: auto;
}
/**
* 1. Address `appearance` set to `searchfield` in Safari and Chrome.
* 2. Address `box-sizing` set to `border-box` in Safari and Chrome.
*/
input[type="search"] {
-webkit-appearance: textfield; /* 1 */
box-sizing: content-box; /* 2 */
}
/**
* Remove inner padding and search cancel button in Safari and Chrome on OS X.
* Safari (but not Chrome) clips the cancel button when the search input has
* padding (and `textfield` appearance).
*/
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
/**
* Define consistent border, margin, and padding.
*/
fieldset {
border: 1px solid #c0c0c0;
margin: 0 2px;
padding: 0.35em 0.625em 0.75em;
}
/**
* 1. Correct `color` not being inherited in IE 8/9/10/11.
* 2. Remove padding so people aren't caught out if they zero out fieldsets.
*/
legend {
border: 0; /* 1 */
padding: 0; /* 2 */
}
/**
* Remove default vertical scrollbar in IE 8/9/10/11.
*/
textarea {
overflow: auto;
}
/**
* Don't inherit the `font-weight` (applied by a rule above).
* NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
*/
optgroup {
font-weight: bold;
}
/* Tables
========================================================================== */
/**
* Remove most spacing between table cells.
*/
table {
border-collapse: collapse;
border-spacing: 0;
}
td,
th {
padding: 0;
}

View File

@ -0,0 +1,38 @@
{%- include 'blocks/head.html.twig' with { title: pageTitle, cssFolderPath: cssFolderPath } %}
<body class="main-page">
<div class="aside aside-left">
<div class="header">
<div class="title">{{ pageTitle }}</div>
</div>
<div class="content">
{%- include 'blocks/main-menu.html.twig' with { mainMenu: mainMenu } %}
</div>
</div>
<div class="aside aside-right">
{%- include 'blocks/header.html.twig' with { imagesFolderPath: imagesFolderPath } %}
<div class="content">
<div class="page-data">
<div class="table">
<div class="part-table">
<div class="row-header">
<div>Код ошибки</div>
<div>Текстовое описание ошибки</div>
</div>
{% for errorValue in errorType.values %}
<div class="row-body">
<div>{{ errorValue.value }}</div>
<div>{{ errorValue.description }}</div>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
</div>
{%- include 'blocks/scripts.html.twig' with { jsFolderPath: jsFolderPath } %}
</body>
</html>

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,14 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg">
<metadata>Copyright (C) 2016 by original authors @ fontello.com</metadata>
<defs>
<font id="social-font" horiz-adv-x="1000" >
<font-face font-family="social-font" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
<missing-glyph horiz-adv-x="1000" />
<glyph glyph-name="vkontakte" unicode="&#xe800;" d="m1070 560q13-36-84-164-13-18-36-48-44-56-50-73-10-23 7-45 10-12 46-46h0l1 0 0-1 1-1q79-73 107-123 2-3 4-7t3-15 0-19-14-15-33-7l-143-3q-13-2-31 3t-29 12l-11 7q-17 12-39 36t-38 43-34 32-32 9q-1 0-4-2t-10-8-12-16-9-29-4-44q0-8-2-15t-4-10l-2-3q-10-11-30-12h-64q-40-3-81 9t-74 29-57 37-40 32l-14 14q-5 5-15 16t-40 51-59 84-68 118-73 152q-4 9-4 15t2 9l2 3q9 11 32 11l153 1q7-1 13-4t9-4l3-2q9-6 13-18 11-28 26-58t23-45l9-16q16-34 31-58t27-38 23-22 19-8 15 3q1 1 3 3t7 12 7 26 5 46 0 69q-1 23-5 41t-7 26l-4 6q-14 19-47 24-8 2 3 14 9 10 21 17 29 14 133 13 46-1 75-7 12-3 19-8t12-13 5-18 2-26 0-30-2-40 0-46q0-6-1-23t0-27 2-22 6-22 13-14q4-1 9-2t15 6 21 19 29 38 38 60q33 58 60 125 2 6 5 10t6 6l2 2 3 1t8 2 11 0l160 1q22 3 36-1t17-10z" horiz-adv-x="1071.4" />
<glyph glyph-name="twitter" unicode="&#xe801;" d="m904 622q-37-54-90-93 0-8 0-23 0-73-21-145t-64-139-103-117-144-82-181-30q-151 0-276 81 19-3 43-3 126 0 224 77-59 2-105 36t-64 89q19-2 34-2 24 0 48 6-63 13-104 62t-41 115v2q38-21 82-23-37 25-59 64t-22 86q0 49 25 91 68-83 164-133t208-55q-5 21-5 41 0 75 53 127t127 53q79 0 132-57 61 12 114 44-20-64-79-100 52 6 104 28z" horiz-adv-x="928.6" />
<glyph glyph-name="facebook" unicode="&#xe802;" d="m535 843v-147h-87q-48 0-65-20t-17-60v-106h164l-22-165h-142v-424h-171v424h-142v165h142v122q0 104 58 161t155 57q82 0 127-7z" horiz-adv-x="571.4" />
</font>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -0,0 +1,86 @@
{%- include 'blocks/head.html.twig' with { title: pageTitle, cssFolderPath: cssFolderPath } %}
<body class="main-page">
<div class="aside aside-left">
<div class="header">
<div class="title">{{ pageTitle }}</div>
</div>
<div class="content">
{%- include 'blocks/main-menu.html.twig' with { mainMenu: mainMenu } %}
</div>
</div>
<div class="aside aside-right">
{%- include 'blocks/header.html.twig' with { imagesFolderPath: imagesFolderPath } %}
<div class="content">
<div class="page-data">
<h2>Протокол общения между сервером и клиентом</h2>
<p class="sub-header">HTTPS</p>
<h2>Стиль построения API</h2>
<p class="sub-header">REST</p>
<h2>Используемая кодировка</h2>
<p class="sub-header">UTF-8</p>
<h2>Допустимые задержки</h2>
<p class="sub-header">Генерация ответа на сервере в среднем занимает меньше 1 секунды.</p>
<h2>Передача параметров</h2>
<p>Параметры передаются в виде JSON-объекта в теле запроса. Для всех запросов должен быть выставлен
Content-Type: application/json. Url Query String не содержит параметров.</p>
<h2>Перечисления</h2>
<p class="sub-header">Перечисления в JSON-объектах передаются в виде типа string.</p>
<h2>Общий вид ответа сервера</h2>
<p>Результат вызова любого метода представляет собоий JSON-объект следующеий структуры:</p>
<div class="table">
<div class="part-table">
<div class="row-header">
<div>Название поля</div>
<div>Тип поля</div>
<div class="text-centered">Название</div>
<div>Обязательность</div>
</div>
<div class="row-body">
<div>result</div>
<div>object</div>
<div>
<p>В случае ошибки содержит null.</p>
<p>В случае успеха содержит результат вызова метода.</p>
</div>
<div>Да</div>
</div>
<div class="row-body">
<div>error_code</div>
<div>int</div>
<div>
<p>В случае ошибки содержит код ошибки 1..999.</p>
<p>В случае успеха содержит 0.</p>
</div>
<div>Да</div>
</div>
<div class="row-body">
<div>error_message</div>
<div>string</div>
<div>
<p>В случае ошибки содержит текстовое описание ошибки.</p>
<p>В случае успеха содержит null.</p>
</div>
<div>Да</div>
</div>
</div>
</div>
</div>
</div>
</div>
{%- include 'blocks/scripts.html.twig' with { jsFolderPath: jsFolderPath } %}
</body>
</html>

View File

@ -0,0 +1,133 @@
$(function () {
$(document).ready(function () {
$('.part-example-response .text-response').css('height', $('.inputs').height() - 21);
$(document).on('click', 'menu li', function (e) {
e.stopPropagation();
$(this).closest('menu').find('li').removeClass('active');
$(this).addClass('active');
});
$(document).on('click', '.show-example-response', function () {
$(this)
.closest('.table')
.toggleClass('example-response-expanded');
});
$(document).on('focus', '.search-block input', function () {
$(this).attr('placeholder', '');
});
$(document).on('blur', '.search-block input', function () {
$(this).attr('placeholder', 'Поиск');
});
$(document).on('click', '.styled-input .null-btn', function () {
$(this)
.closest('.styled-input')
.find('input')
.val('NULL');
});
$(document).on('focus', '.disabled input', function () {
$(this)
.closest('label')
.removeClass('disabled');
});
$(document).on('click', '.run-btn', function (e) {
var model = serializeInputs('.inputs');
console.log('Send data: ' + JSON.stringify(model));
$.ajax({
type: 'POST',
data: JSON.stringify(model),
contentType: 'application/json',
dataType: 'json',
url: 'json/response.json'
})
.done(
function (response) {
var json = JSON.stringify(response, null, 4);
json = highlightJson(json);
$('.text-response').html(json);
})
.fail(
function () {
alert('Ошибка запроса.');
});
});
$(document).on('keyup', '.search-block input', function (e) {
var $searchInput = $(this);
var $typeaheadContainer = $searchInput.closest('.search-block').find('.typeahead-container');
var $typeaheadContent = $typeaheadContainer.find('.typeahead-content');
$.ajax({
type: 'POST',
contentType: 'application/json',
dataType: 'json',
url: 'json/methods.json'
})
.done(
function (response) {
var itemsLink = '';
response
.filter(function (item) {
return item.name.toLowerCase().indexOf($searchInput.val().toLowerCase()) >= 0;
})
.forEach(function (item) {
itemsLink += '<a href="' + item.url + '">' + item.name + '</a>'
});
$typeaheadContent.html(itemsLink);
if (itemsLink != '') {
$typeaheadContainer.removeClass('typeahead-container--hide');
} else {
$typeaheadContainer.addClass('typeahead-container--hide');
}
})
.fail(
function () {
alert('Ошибка запроса.');
});
});
$(document).on('blur', '.search-block input', function (e) {
$(this).closest('.search-block').find('.typeahead-container').addClass('typeahead-container--hide');
});
$(document).on('click', '.styled-input .clear-btn', function (e) {
e.preventDefault();
$(this)
.closest('label')
.addClass('disabled')
.find('input')
.val('');
});
function serializeInputs(containerClass) {
var model = {};
$(containerClass + ' label:not(.disabled) input,' + containerClass + ' label:not(.disabled) select')
.each(function () {
model[$(this).data('name')] = $(this).val() == 'NULL' ? null : $(this).val();
});
return model;
}
function highlightJson(jsonString) {
jsonString = jsonString.replace(/(".*":\s)(".*")/ig, "$1<span class='text-string'>$2</span>");
jsonString = jsonString.replace(/(".*":\s)(\d*)/ig, "$1<span class='text-digit'>$2</span>");
return jsonString
}
});
});

View File

@ -0,0 +1,156 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>tiApi</title>
<link type="text/css" rel="stylesheet" href="css/main.css?v=1.07" media="all">
<link type="text/css" rel="stylesheet" href="css/fonts.css?v=1.07" media="all">
<link type="text/css" rel="stylesheet" href="css/normalize.css" media="all">
</head>
<body class="main-page">
<div class="aside aside-left">
<div class="header">
<div class="title">API для «ДБО»</div>
</div>
<div class="content">
<menu class="main">
<li><a href="index.html">Общие принципы построения API</a></li>
<li class="active"><a href="methods.html">Методы</a></li>
<li><a href="notification.html">PUSH-нотификации</a></li>
<li><a href="structure_enumeration.html">Структура данных</a></li>
<li><a href="versioning.html">Версионнирование API</a></li>
<li><a href="errors.html">Список возможных ошибок</a></li>
</menu>
<menu class="secondary">
<li><a>Пользователь</a></li>
<li class="active"><a>Карты</a>
<menu class="child">
<li class="active"><a>Список карт</a></li>
<li><a>Детали карты</a></li>
<li><a>Изменить имя</a></li>
<li><a>Изменить номер для SMS основного номера</a></li>
<li><a>Заблокировать карту</a></li>
</menu>
</li>
<li><a>Общее</a></li>
<li><a>Платежи</a></li>
<li><a>Избранное</a></li>
<li><a>Баланс близких</a></li>
<li><a>Транзакции</a></li>
<li><a>Серверные методы</a></li>
</menu>
</div>
</div>
<div class="aside aside-right">
<div class="header">
<div class="search-block">
<i class="icon-search"></i>
<input type="text" placeholder="Поиск">
<div class="typeahead-container typeahead-container--hide"><div class="typeahead-content"></div></div>
</div>
<div class="logo">
<img src="images/logo.png">
</div>
</div>
<div class="content">
<div class="page-data">
<h2>Метод</h2>
<p class="sub-header">POST /card/listing/</p>
<h2>Параметры</h2>
<div class="table example-response-expanded">
<div class="part-table">
<div class="row-header">
<div>Название параметра</div>
<div>Тип параметра</div>
<div class="text-centered">Описание</div>
<div>Обязательность</div>
</div>
<div class="row-body">
<div>session_id</div>
<div>string[32]</div>
<div>Идентификатор сессии</div>
<div>Да</div>
</div>
</div>
<div class="part-block">
<a class="show-example-response">Пример запроса</a>
</div>
<div class="part-example-response">
<div class="inputs">
<label>
registraton_id<br>
<input type="text" data-name="registraton_id">
</label>
<label>
confirmation_id<br>
<div class="styled-input">
<input type="text" value="2428" data-name="confirmation_id">
<div class="clear-btn">×</div>
<div class="null-btn">NULL</div>
</div>
</label>
<label class="disabled">
code<br>
<div class="styled-input">
<input type="text" data-name="code">
<div class="clear-btn">×</div>
<div class="null-btn">NULL</div>
</div>
</label>
<label>
поле<br>
<div class="styled-select">
<select data-name="field">
<option>5.45</option>
<option>6</option>
<option>10</option>
</select>
</div>
</label>
<button class="btn run-btn">
Выполнить
</button>
</div>
<div class="text-response"></div>
</div>
</div>
<h2>Возможные ошибки</h2>
<p class="sub-header">#Код 2 — пользователь не найден.</p>
<h2>Результат</h2>
<p>Объект следующей структуры:</p>
<div class="table example-response-expanded">
<div class="part-table">
<div class="row-header">
<div>Название поля</div>
<div>Тип поля</div>
<div class="text-centered">Описание</div>
<div>Обязательность</div>
</div>
<div class="row-body">
<div>items</div>
<div><a class="info" href="structure_objects.html">Card</a>[]</div>
<div>Список карт</div>
<div>Да</div>
</div>
</div>
</div>
<h2>Комментарий</h2>
<p class="sub-header">Изображения возвращаются подходящего для платформы пользователя размера.</p>
</div>
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<script type="text/javascript" src="js/main.js?v=1.02"></script>
</body>
</html>

View File

@ -0,0 +1,126 @@
{%- include 'blocks/head.html.twig' with { title: pageTitle, cssFolderPath: cssFolderPath } %}
<body class="main-page">
<div class="aside aside-left">
<div class="header">
<div class="title">{{ pageTitle }}</div>
</div>
<div class="content">
{%- include 'blocks/main-menu.html.twig' with { mainMenu: mainMenu } %}
<menu class="secondary">
{% for menu in menus %}
{% include 'blocks/secondary-menu.html.twig' with {
menu: menu,
menuTitle: menu.title,
activeItemTypeName: name
} %}
{% endfor %}
</menu>
</div>
</div>
<div class="aside aside-right">
{%- include 'blocks/header.html.twig' with { imagesFolderPath: imagesFolderPath } %}
<div class="content">
<div class="page-data">
<h2>Метод</h2>
<p class="sub-header">POST {{ url }}</p>
<h2>Параметры</h2>
<div class="table example-response-expanded">
<div class="part-table">
<div class="row-header">
<div>Название параметра</div>
<div>Тип параметра</div>
<div class="text-centered">Описание</div>
<div>Обязательность</div>
</div>
{% for field in requestFields -%}
{%- include 'blocks/field-row.html.twig' with {
field: field,
objectsLinks: objectsLinks
} %}
{%- endfor %}
</div>
<div class="part-block">
<a class="show-example-response">Пример запроса</a>
</div>
<div class="part-example-response">
<div class="inputs">
{% for field in requestFields -%}
<label>
{{ field.jsonName }}<br>
{% if field.type.values is not empty -%}
<div class="styled-select">
<select data-name="{{ field.jsonName }}">
{% for value in field.type.values %}
<option>{{ value.value }}</option>
{% endfor %}
</select>
</div>
{%- else %}
{%- if field.optional or field.nullable -%}
<div class="styled-input">
<input type="text" data-name="{{ field.jsonName }}">
{% if field.optional -%}
<div class="clear-btn">×</div>
{%- endif -%}
{% if field.nullable -%}
<div class="null-btn">NULL</div>
{%- endif %}
</div>
{%- else %}
<input type="text" data-name="{{ field.jsonName }}">
{% endif %}
{%- endif %}
</label>
{% endfor %}
<button class="btn run-btn">
Выполнить
</button>
</div>
<div class="text-response"></div>
</div>
</div>
<h2>Возможные ошибки</h2>
{% for value in errorsEnumeration.values -%}
{%- if value.value in errorsEnumeration.allowedValues %}
<p class="sub-header">#Код {{ value.value }}{{ value.description }}</p>
{%- endif -%}
{%- endfor %}
<h2>Результат</h2>
<p>Объект следующей структуры:</p>
<div class="table example-response-expanded">
<div class="part-table">
<div class="row-header">
<div>Название поля</div>
<div>Тип поля</div>
<div class="text-centered">Описание</div>
<div>Обязательность</div>
</div>
{% for field in responseFields -%}
{%- include 'blocks/field-row.html.twig' with {
field: field,
objectsLinks: objectsLinks
} %}
{%- endfor %}
</div>
</div>
<h2>Комментарий</h2>
<p class="sub-header">{{ description }}</p>
</div>
</div>
</div>
{%- include 'blocks/scripts.html.twig' with { jsFolderPath: jsFolderPath } %}
</body>
</html>

View File

@ -0,0 +1,64 @@
{%- include 'blocks/head.html.twig' with { title: pageTitle, cssFolderPath: cssFolderPath } %}
<body class="main-page">
<div class="aside aside-left">
<div class="header">
<div class="title">API для «ДБО»</div>
</div>
<div class="content">
{%- include 'blocks/main-menu.html.twig' with { mainMenu: mainMenu } %}
<menu class="secondary">
<li><a>Android</a></li>
<li class="active"><a>iOS</a></li>
<li><a>Windows Phone</a></li>
</menu>
</div>
</div>
<div class="aside aside-right">
{%- include 'blocks/header.html.twig' with { imagesFolderPath: imagesFolderPath } %}
<div class="content">
<div class="page-data">
<h2>Официальная документация</h2>
<p class="sub-header"><a href="http://apple.com" class="info" target="_blank">Ссылка от Apple</a></p>
<h2>Структура объекта нотификации</h2>
<div class="example-response">
<div class="text-response">{
"response": <span class="text-digit"></span>{
"count": <span class="text-digit">2428</span>,
"items": <span class="text-digit"></span>
[
{
"id": <span class="text-digit">54832560</span>,
"first_name": <span class="text-digit"></span><span class="text-string">"Anyutka"</span>,
"last_name": <span class="text-digit"></span><span class="text-string">"Kiseleva"</span>,
"photo_50": <span class="text-digit"></span><span class="text-string">"http://cs417830.v...4a7/Y-zZa02zvmQ.jpg"</span>
},
{
"id": <span class="text-digit">221194575</span>,
"first_name": <span class="text-digit"></span><span class="text-string">"Lera"</span>,
"last_name": <span class="text-digit"></span><span class="text-string">"Chistova"</span>,
"photo_50": <span class="text-digit"></span><span class="text-string">"http://cs322328.v...0fb/qi2nofkqneI.jpg"</span>
}
]
}
}</div>
</div>
<p class="sub-header">
&lt;type&gt; - Тип PUSH-нотификации. ( <a href="/methods.html" class="info">PushType</a> ) <br/>
&lt;data_id&gt; - Идентификатор карты или акции<br/>
&lt;text&gt; - Текст PUSH-нотификации.</p>
</div>
</div>
</div>
{%- include 'blocks/scripts.html.twig' with { jsFolderPath: jsFolderPath } %}
</body>
</html>

View File

@ -0,0 +1,56 @@
{%- include 'blocks/head.html.twig' with { title: pageTitle, cssFolderPath: cssFolderPath } %}
<body class="main-page">
<div class="aside aside-left">
<div class="header">
<div class="title">{{ pageTitle }}</div>
</div>
<div class="content">
{%- include 'blocks/main-menu.html.twig' %}
<menu class="secondary">
{% include 'blocks/secondary-menu.html.twig' with {
menu: enumsMenu,
menuTitle: "Перечисления",
activeItemTypeName: name
} %}
{% include 'blocks/secondary-menu.html.twig' with {
menu: classesMenu,
menuTitle: "Объекты"
} %}
</menu>
</div>
</div>
<div class="aside aside-right">
{%- include 'blocks/header.html.twig' with { imagesFolderPath: imagesFolderPath } %}
<div class="content">
<div class="page-data">
<h2>Описание</h2>
<p class="sub-header">{{ description }}</p>
<h2>Возможные значения</h2>
<div class="table table--small">
<div class="part-table">
<div class="row-header">
<div>Значения</div>
<div>Описание</div>
</div>
{% for value in values %}
<div class="row-body">
<div>{{ value.value }}</div>
<div>{{ value.description }}</div>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
</div>
{%- include 'blocks/scripts.html.twig' with { jsFolderPath: jsFolderPath } %}
</body>
</html>

View File

@ -0,0 +1,57 @@
{%- include 'blocks/head.html.twig' with { title: pageTitle, cssFolderPath: cssFolderPath } %}
<body class="main-page">
<div class="aside aside-left">
<div class="header">
<div class="title">{{ pageTitle }}</div>
</div>
<div class="content">
{%- include 'blocks/main-menu.html.twig' with { mainMenu: mainMenu } %}
<menu class="secondary">
{% include 'blocks/secondary-menu.html.twig' with {
menu: enumsMenu,
menuTitle: "Перечисления"
} %}
{% include 'blocks/secondary-menu.html.twig' with {
menu: classesMenu,
menuTitle: "Объекты"
} %}
</menu>
</div>
</div>
<div class="aside aside-right">
{%- include 'blocks/header.html.twig' with { imagesFolderPath: imagesFolderPath } %}
<div class="content">
<div class="page-data">
<h2>Описание</h2>
<p class="sub-header">Карта</p>
<h2>Структура данных</h2>
<div class="table">
<div class="part-table">
<div class="row-header">
<div>Название поля</div>
<div>Тип поля</div>
<div class="text-centered">Описание</div>
<div>Обязательность</div>
</div>
{% for field in fields -%}
{%- include 'blocks/field-row.html.twig' with {
field: field,
objectsLinks: objectsLinks
} %}
{%- endfor %}
</div>
</div>
</div>
</div>
</div>
{%- include 'blocks/scripts.html.twig' with { jsFolderPath: jsFolderPath } %}
</body>
</html>

View File

@ -0,0 +1,7 @@
{% macro formatNullable(expr, nullable) %}
{{- expr -}}{%- if nullable -%}?{%- endif -%}
{% endmacro %}
{% macro optionalDescription(optional) %}
{%- if optional -%}Нет{%- else -%}Да{%- endif -%}
{% endmacro %}

View File

@ -0,0 +1,59 @@
{%- include 'blocks/head.html.twig' with { title: pageTitle, cssFolderPath: cssFolderPath } %}
<body class="main-page">
<div class="aside aside-left">
<div class="header">
<div class="title">{{ pageTitle }}</div>
</div>
<div class="content">
{%- include 'blocks/main-menu.html.twig' with { mainMenu: mainMenu } %}
</div>
</div>
<div class="aside aside-right">
{%- include 'blocks/header.html.twig' with { imagesFolderPath: imagesFolderPath } %}
<div class="content">
<div class="page-data">
<h2>Описание</h2>
<p class="sub-header">Необходимо иметь возможность поддержки нескольких версий API (для одновременной работы нескольких версий приложения). Также необходимо предусмотреть принудительное обновление какой-либо из версий.</p>
<p class="sub-header"> Версии API будут размещаться на url-адресах вида &lt;base_url&gt;/v&lt;version_number&gt;/, где &lt;version_number&gt; - версия API.</p>
<p class="sub-header">При вызове любого метода в случае, если вызываемая версия API требует обновления приложения, сервер должен вернуть ошибку:<br/>
"Версия приложения устарела. Необходимо обновить приложение. Код 1."</p>
<p class="sub-header">При этом приложение должно показать пользователю диалог с предложением установить новую версию из маркета, а остальные функции должны стать недоступными.
</p>
<h2>Пример</h2>
<p class="sub-header">Первая версия API будет располагаться по адресу: &lt;base_url&gt;/v1/.<br/>
В тот момент, когда эта версия API перестанет поддерживаться, на все запросы этой версии API сервер должен возвращать следующий ответ:</p>
<div class="example-response">
<div class="text-response">{
"response": <span class="text-digit"></span>{
"count": <span class="text-digit">2428</span>,
"items": <span class="text-digit"></span>
[
{
"id": <span class="text-digit">54832560</span>,
"first_name": <span class="text-digit"></span><span class="text-string">"Anyutka"</span>,
"last_name": <span class="text-digit"></span><span class="text-string">"Kiseleva"</span>,
"photo_50": <span class="text-digit"></span><span class="text-string">"http://cs417830.v...4a7/Y-zZa02zvmQ.jpg"</span>
},
{
"id": <span class="text-digit">221194575</span>,
"first_name": <span class="text-digit"></span><span class="text-string">"Lera"</span>,
"last_name": <span class="text-digit"></span><span class="text-string">"Chistova"</span>,
"photo_50": <span class="text-digit"></span><span class="text-string">"http://cs322328.v...0fb/qi2nofkqneI.jpg"</span>
}
]
}
}</div>
</div>
</div>
</div>
</div>
{%- include 'blocks/scripts.html.twig' with { jsFolderPath: jsFolderPath } %}
</body>
</html>