feat: VivesPOS landing on Winter CMS 1.2 — theme + plugin + Dockerfile
Some checks are pending
Module sub-split / Sub-split (push) Waiting to run

- Base: wintercms/winter branch 1.2 (full framework)
- Theme vivespos: Canvas 7 + Bootstrap 5 CDN, custom CSS
- Layout: deferred GTM/GA4 tracking, JSON-LD SoftwareApplication
- Partials: hero (offline-first), features, modes (offline/nube toggle),
  screenshots, pricing (3 planes), comparison, FAQ, CTA
- Plugin VivesPOS.Site with ContactForm
- Dockerfile: PHP 8.2 Apache, port 80, healthcheck
- Added winter/wn-pages, blog, sitemap, seo plugins
- Active theme set to vivespos
This commit is contained in:
2026-08-21 19:29:00 -06:00
commit 1f72193a64
3266 changed files with 531480 additions and 0 deletions

View File

@@ -0,0 +1,19 @@
# Autocomplete
### Autocomplete
Autocomplete control.
<input
class="form-control"
placeholder="Search for something or else"
data-control="autocomplete"
data-source="something: 'Something', else: 'Else'" />
## JavaScript API
```js
$('input').autocomplete({
source: { something: 'Something', else: 'Else' }
})
```

View File

@@ -0,0 +1,13 @@
Display a breadcrumb on the page.
# Example
<div style="padding: 20px">
<div class="control-breadcrumb">
<ul>
<li><a href="#">Dash Board</a></li>
<li><a href="#">Blog Posts</a></li>
<li>Edit Post</li>
</ul>
</div>
</div>

View File

@@ -0,0 +1,63 @@
# Button
## Buttons
### Button tags
Use the button classes on an `<a>`, `<button>`, or `<input>` element.
<a class="btn btn-default" href="#" role="button">Link</a>
<button class="btn btn-default" type="submit">Button</button>
<input class="btn btn-default" type="button" value="Input">
<input class="btn btn-default" type="submit" value="Submit">
### Options
Use any of the available button classes to quickly create a styled button.
<!-- Standard button -->
<button type="button" class="btn btn-default">Default</button>
<!-- Provides extra visual weight and identifies the primary action in a set of buttons -->
<button type="button" class="btn btn-primary">Primary</button>
<!-- Indicates a successful or positive action -->
<button type="button" class="btn btn-success">Success</button>
<!-- Contextual button for informational alert messages -->
<button type="button" class="btn btn-info">Info</button>
<!-- Indicates caution should be taken with this action -->
<button type="button" class="btn btn-warning">Warning</button>
<!-- Indicates a dangerous or potentially negative action -->
<button type="button" class="btn btn-danger">Danger</button>
<!-- Deemphasize a button by making it look like a link while maintaining button behavior -->
<button type="button" class="btn btn-link">Link</button>
### Sizes
Fancy larger or smaller buttons? Add `.btn-lg`, `.btn-sm`, or `.btn-xs` for additional sizes.
<p>
<button type="button" class="btn btn-primary btn-lg">Large button</button>
<button type="button" class="btn btn-default btn-lg">Large button</button>
</p>
<p>
<button type="button" class="btn btn-primary">Default button</button>
<button type="button" class="btn btn-default">Default button</button>
</p>
<p>
<button type="button" class="btn btn-primary btn-sm">Small button</button>
<button type="button" class="btn btn-default btn-sm">Small button</button>
</p>
<p>
<button type="button" class="btn btn-primary btn-xs">Extra small button</button>
<button type="button" class="btn btn-default btn-xs">Extra small button</button>
</p>
Create block level buttons—those that span the full width of a parent— by adding .btn-block.
<button type="button" class="btn btn-primary btn-lg btn-block">Block level button</button>
<button type="button" class="btn btn-default btn-lg btn-block">Block level button</button>

View File

@@ -0,0 +1,66 @@
# Callout
### Callout
Displays a detailed message to the user, also allowing it to be dismissed.
<div class="callout fade in callout-warning">
<button
type="button"
class="close"
data-dismiss="callout"
aria-hidden="true">&times;</button>
<div class="header">
<i class="icon-warning"></i>
<h3>Warning warning</h3>
<p>My arms are flailing wildly</p>
</div>
<div class="content">
<p>Insert coin(s) to begin play</p>
</div>
</div>
### No sub-header
Include the `no-subheader` class to omit the sub heading.
<div class="callout fade in callout-info no-subheader">
<div class="header">
<i class="icon-info"></i>
<h3>Incoming unicorn</h3>
</div>
</div>
### No icon
Include the `no-icon` class to omit the icon.
<div class="callout fade in callout-danger no-icon">
<div class="header">
<h3>There was a hull breach</h3>
<ul>
<li>Get to the chopper</li>
</ul>
</div>
</div>
### No header
<div class="callout fade in callout-success">
<div class="content">
<p>Something good happened</p>
<ul>
<li>You found a pony</li>
</ul>
</div>
</div>
### Data attributes:
- data-dismiss="callout" - when assigned to an element, the callout hides on click
## JavaScript API
### Events
- close.oc.callout - triggered when the callout is closed

View File

@@ -0,0 +1,127 @@
# Chart
<a name="pie-chart" class="anchor" href="#pie-chart"></a>
## Pie chart
The pie chart outputs information as a circle diagram, with optional label in the center. Example markup:
<div
class="control-chart centered wrap-legend"
data-control="chart-pie"
data-size="200"
data-center-text="100">
<ul>
<li>Label 1 <span>100</span></li>
<li>Label 2 <span>100</span></li>
<li>Label 3 <span>100</span></li>
</ul>
</div>
![image](https://github.com/wintercms/docs/blob/main/images/traffic-sources.png?raw=true) {.img-responsive .frame}
<a name="line-chart" class="anchor" href="#line-chart"></a>
## Line chart
The next example shows a line chart markup. Data sets are defined with the SPAN elements inside the chart element.
<div
data-control="chart-line"
data-time-mode="weeks"
style="height: 200px"
data-chart-options="xaxis: {mode: 'time'}">
<span
data-chart="dataset"
data-set-color="#008dc9"
data-set-data="[1477857082000, 400], [1477943482000, 380], [1478029882000, 340], [1478116282000, 540], [1478202682000, 440], [1478289082000, 360], [1478375482000, 220]"
data-set-name="Visits">
</span>
</div>
![image](https://github.com/wintercms/docs/blob/main/images/line-chart.png?raw=true) {.img-responsive .frame}
<a name="bar-chart" class="anchor" href="#bar-chart"></a>
## Bar chart
The next example shows a bar chart markup. The **wrap-legend** class is optional, it manages the legend layout. The **data-height** and **data-full-width** attributes are optional as well.
<div
class="control-chart wrap-legend"
data-control="chart-bar"
data-height="100"
data-full-width="1">
<ul>
<li>Label 1 <span>100</span></li>
<li>Label 2 <span>100</span></li>
<li>Label 3 <span>100</span></li>
</ul>
</div>
![image](https://github.com/wintercms/docs/blob/main/images/bar-chart.png?raw=true) {.img-responsive .frame}
# Example
<div
class="control-chart centered wrap-legend"
data-control="chart-pie"
data-size="200"
data-center-text="100">
<ul>
<li>Label 1 <span>100</span></li>
<li>Label 2 <span>100</span></li>
<li>Label 3 <span>100</span></li>
</ul>
</div>
<div
class="control-chart wrap-legend"
data-control="chart-bar"
data-height="100"
data-full-width="1">
<ul>
<li>Label 1 <span>100</span></li>
<li>Label 2 <span>100</span></li>
<li>Label 3 <span>100</span></li>
</ul>
</div>
<a name="bar-chart" class="anchor" href="#bar-chart"></a>
## Status list
A list of statuses and values
# Example
<div class="control-status-list">
<ul>
<li>
<span class="status-icon success"><i class="icon-check"></i></span>
<span class="status-text success">Software is up to date</span>
<a href="#" class="status-label link">Update</a>
</li>
<li>
<span class="status-icon warning"><i class="icon-exclamation"></i></span>
<span class="status-text warning">Some issues need attention</span>
<a href="#" class="status-label link">View</a>
</li>
<li>
<span class="status-icon"><i class="icon-info"></i></span>
<span class="status-text">System build</span>
<span class="status-label primary">313</span>
</li>
<li>
<span class="status-icon"><i class="icon-info"></i></span>
<span class="status-text">Event log items</span>
<span class="status-label primary">200</span>
</li>
<li>
<span class="status-icon"><i class="icon-info"></i></span>
<span class="status-text">Online since</span>
<span class="status-label link">4th April 2014</span>
</li>
</ul>
</div>

View File

@@ -0,0 +1,102 @@
# Checkbox
### Checkbox
Allows a user to select from a small set of binary options.
<div class="checkbox custom-checkbox">
<input name="checkbox" value="1" type="checkbox" id="checkbox1" />
<label for="checkbox1">Checkbox</label>
</div>
### Checkbox lists
Allows a user to select from a list of binary options.
<div class="form-group checkboxlist-field">
<label>Checkbox list (hard-coded) example</label>
<div class="field-checkboxlist">
<!-- Quick selection (start) -->
<div class="checkboxlist-controls">
<div>
<a href="javascript:;" data-field-checkboxlist-all><i class="icon-check-square"></i> <?= e(trans('backend::lang.form.select_all')) ?></a>
</div>
<div>
<a href="javascript:;" data-field-checkboxlist-none><i class="icon-eraser"></i> <?= e(trans('backend::lang.form.select_none')) ?></a>
</div>
</div>
<!-- Quick selection (end) -->
<div class="field-checkboxlist-container">
<p class="help-block before-field">What cars would you like in your garage?</p>
<div class="checkbox custom-checkbox" tabindex="0">
<input id="checkbox-example1" name="checkbox" value="1" type="checkbox" checked="checked" aria-checked="true" />
<label for="checkbox-example1"> Dodge Viper </label>
<p class="help-block">Do not send new comment notifications.</p>
</div>
<div class="checkbox custom-checkbox" tabindex="0">
<input id="checkbox-example2" name="checkbox" value="2" type="checkbox" aria-checked="false" />
<label for="checkbox-example2"> GM Corvette </label>
<p class="help-block">Send new comment notifications only to post author.</p>
</div>
<div class="checkbox custom-checkbox" tabindex="0">
<input id="checkbox-example3" name="checkbox" value="3" type="checkbox" aria-checked="mixed" />
<label for="checkbox-example3"> Porsche Boxter </label>
<p class="help-block">Notify all users who have permissions to receive blog notifications.</p>
</div>
</div>
</div>
</div>
### Indeterminate checkboxes
<div class="checkbox custom-checkbox is-indeterminate">
<input name="checkbox" value="1" type="checkbox" id="checkbox1" data-checked="1" />
<label for="checkbox1">Checkbox</label>
</div>
The `data-checked` attribute may have one of three values: 0 (off), 1 (indeterminate) or 2 (on).
### Radio
<div class="radio custom-radio">
<input name="radio" value="1" type="radio" id="radio_1" />
<label for="radio_1">Paris</label>
</div>
<div class="radio custom-radio">
<input checked="checked" name="radio" value="2" type="radio" id="radio_2" />
<label for="radio_2">Dubai</label>
</div>
<div class="radio custom-radio">
<input name="radio" value="3" type="radio" id="radio_3" />
<label for="radio_3">New Zealand</label>
</div>
### Slider
<label class="custom-switch">
<input type="checkbox" />
<span><span>On</span><span>Off</span></span>
<a class="slide-button"></a>
</label>
### Balloon selector
<div data-control="balloon-selector" class="control-balloon-selector">
<ul>
<li data-value="1" class="active">One</li>
<li data-value="2">Two</li>
<li data-value="3">Three</li>
</ul>
<input type="hidden" name="balloonValue" value="1" />
</div>
If you don't define `data-control="balloon-selector"` then the control will act as a static list of labels.
<div class="control-balloon-selector">
<ul>
<li>Monday</li>
<li>Tuesday</li>
<li>Happy days!</li>
</ul>
</div>

View File

@@ -0,0 +1,102 @@
# Date Pickers
Renders a date picker, time picker, or both. The input associated to each control acts as a facade, the final value is stored in an underlying hidden input, called a data locker.
## Examples
### Date Picker
<div data-control="datepicker">
<!-- Date -->
<input
type="text"
class="form-control"
placeholder="Select a date"
data-datepicker />
<!-- Data locker -->
<input
type="hidden"
name="my_date"
data-datetime-value
/>
</div>
### Time Picker
<div data-control="datepicker">
<!-- Time -->
<input
type="text"
class="form-control"
placeholder="Select a time"
data-timepicker />
<!-- Data locker -->
<input
type="hidden"
name="my_date"
data-datetime-value
/>
</div>
### Date & Time Picker
<div data-control="datepicker">
<div class="row">
<div class="col-md-6">
<!-- Date -->
<input
type="text"
class="form-control"
placeholder="Select a date"
data-datepicker />
</div>
<div class="col-md-6">
<!-- Time -->
<input
type="text"
class="form-control"
placeholder="Select a time"
data-timepicker />
</div>
</div>
<!-- Data locker -->
<input
type="hidden"
name="my_date"
data-datetime-value
/>
</div>
## Locale and timezone handling
The date picker handles timezone and locale preferences automatically. Locale preferences will provide the date format for the region. The timezone setting is used to convert the chosen value to a uniform timezone, commonly UTC. These features are not enabled by default and require adding `<meta />` tags to the page.
```html
<meta name="app-timezone" content="UTC">
<meta name="backend-timezone" content="Australia/Sydney">
<meta name="backend-locale" content="en-au">
```
When a date is selected, it will be converted from the `backend-timezone` to the `app-timezone` for normalized storage.
> **Note**: Locale values are supplied by the Moment.js library.
## Supported data attributes
- data-control="datepicker" - enables the plugin on an element
- data-format="YYYY-MM-DD" - display format
- data-min-date="value" - minimum date to allow
- data-max-date="value" - maximum date to allow
- data-year-range="10" - range of years to display
## JavaScript API
```js
$('div#datepicker').datePicker({
format: 'YYYY-MM-DD',
yearRange: 10
})
```

View File

@@ -0,0 +1,27 @@
# Drag.Scroll
Allows the elements with `overflow: hidden` to be dragged.
### Example
Drag the area above left-to-right.
<div id="scrollExample">
<div class="scroll-stripes-example"></div>
</div>
<style>
#scrollExample {
width: 100%; height: 50px; overflow: hidden;
}
.scroll-stripes-example {
height: 50px; width: 5000px;
background-image: linear-gradient(90deg, gray, white, gray);
background-size: 500px 50px;
}
</style>
<script>
$('#scrollExample').dragScroll();
</script>

View File

@@ -0,0 +1,108 @@
# Drag.Sort
Allows the dragging and sorting of lists.
### Example
Sort the buttons
<ol id="sortExample">
<li><a class="btn btn-sm btn-default">First</a></li>
<li><a class="btn btn-sm btn-primary">Second</a></li>
<li><a class="btn btn-sm btn-success">Third</a></li>
</ol>
<script>
$('#sortExample').sortable()
</script>
<style>
body.dragging, body.dragging * {
cursor: move !important
}
.dragged {
position: absolute; opacity: 0.5; z-index: 2000;
}
#sortExample li.placeholder {
position: relative;
}
</style>
## JavaScript API
The `sortable()` method must be invoked on valid containers, meaning they must match the containerSelector option.
`.sortable('enable')`
Enable all instantiated sortables in the set of matched elements
`.sortable('disable')`
Disable all instantiated sortables in the set of matched elements
`.sortable('refresh')`
Reset all cached element dimensions
`.sortable('destroy')`
Remove the sortable plugin from the set of matched elements
`.sortable('serialize')`
Serialize all selected containers. Returns a jQuery object . Use .get() to retrieve the array, if needed.
### Supported options
- `useAnimation`: Use animation when an item is removed or inserted into the tree.
- `usePlaceholderClone`: Placeholder should be a clone of the item being dragged.
- `afterMove`: This is executed after the placeholder has been moved. $closestItemOrContainer contains the closest item, the placeholder has been put at or the closest empty Container, the placeholder has been appended to.
- `containerPath`: The exact css path between the container and its items, e.g. "> tbody"
- `containerSelector`: The css selector of the containers
- `distance`: Distance the mouse has to travel to start dragging
- `delay`: Time in milliseconds after mousedown until dragging should start. This option can be used to prevent unwanted drags when clicking on an element.
- `handle`: The css selector of the drag handle
- `itemPath`: The exact css path between the item and its subcontainers. It should only match the immediate items of a container. No item of a subcontainer should be matched. E.g. for ol>div>li the itemPath is "> div"
- `itemSelector`: The css selector of the items
- `bodyClass`: The class given to "body" while an item is being dragged
- `draggedClass`: The class giving to an item while being dragged
- `isValidTarget`: Check if the dragged item may be inside the container. Use with care, since the search for a valid container entails a depth first search and may be quite expensive.
- `onCancel`: Executed before onDrop if placeholder is detached. This happens if pullPlaceholder is set to false and the drop occurs outside a container.
- `onDrag`: Executed at the beginning of a mouse move event. The Placeholder has not been moved yet.
- `onDragStart`: Called after the drag has been started, that is the mouse button is being held down and the mouse is moving. The container is the closest initialized container. Therefore it might not be the container, that actually contains the item.
- `onDrop`: Called when the mouse button is being released
- `onMousedown`: Called on mousedown. If falsy value is returned, the dragging will not start. Ignore if element clicked is input, select or textarea
- `placeholderClass`: The class of the placeholder (must match placeholder option markup)
- `placeholder`: Template for the placeholder. Can be any valid jQuery input e.g. a string, a DOM element. The placeholder must have the class "placeholder"
- `pullPlaceholder`: If true, the position of the placeholder is calculated on every mousemove. If false, it is only calculated when the mouse is above a container.
- `serialize`: Specifies serialization of the container group. The pair $parent/$children is either container/items or item/subcontainers.
- `tolerance`: Set tolerance while dragging. Positive values decrease sensitivity, negative values increase it.
### Supported options (container specific)
- `drag`: If true, items can be dragged from this container
- `drop`: If true, items can be droped onto this container
- `exclude`: Exclude items from being draggable, if the selector matches the item
- `nested`: If true, search for nested containers within an item.If you nest containers, either the original selector with which you call the plugin must only match the top containers, or you need to specify a group (see the bootstrap nav example)
- `vertical`: If true, the items are assumed to be arranged vertically

View File

@@ -0,0 +1,52 @@
# Drag.Value
Allows the dragging of elements that result in a custom value when dropped.
<p>
<input placeholder="Drag a button below to me" class="form-control" />
</p>
<button
class="btn btn-default"
data-control="dragvalue"
data-text-value="Winter">
Drop "Foo"
</button>
<button
class="btn btn-default"
data-control="dragvalue"
data-text-value="CMS">
Drop "Bar"
</button>
### Clickable
You can make elements clickable from another input by defining `data-drag-click="true"`.
<p>
<input placeholder="Click on me first, then click a label below" class="form-control" />
</p>
<div class="control-balloon-selector">
<ul>
<li
data-control="dragvalue"
data-text-value="Richie"
data-drag-click="true">
Monday
</li>
<li
data-control="dragvalue"
data-text-value="Potsie"
data-drag-click="true">
Tuesday
</li>
<li
data-control="dragvalue"
data-text-value="The Fonz"
data-drag-click="true">
Happy days!
</li>
</ul>
</div>

View File

@@ -0,0 +1,43 @@
Customized dropdown menu
### Small dropdown
<div class="dropdown">
<a href="#" data-toggle="dropdown" class="btn btn-primary wn-icon-plus">Add small</a>
<ul class="dropdown-menu" role="menu" data-dropdown-title="Add something small">
<li role="presentation"><a role="menuitem" tabindex="-1" href="#" class="wn-icon-folder">Group</a></li>
<li role="presentation"><a role="menuitem" tabindex="-1" href="#" class="wn-icon-copy">Page</a></li>
</ul>
</div>
### Drop "up"
Add the `dropup` class to the dropdown container and the dropdown will appear in an upward direction.
<div class="dropdown dropup">
...
</div>
### Large dropdown
<div class="dropdown">
<a href="#" data-toggle="dropdown" class="btn btn-primary wn-icon-plus">Add large</a>
<ul class="dropdown-menu" role="menu" data-dropdown-title="Add something large">
<li role="presentation"><a role="menuitem" tabindex="-1" href="#" class="wn-icon-folder">Group</a></li>
<li role="presentation"><a role="menuitem" tabindex="-1" href="#" class="wn-icon-copy">Page</a></li>
<li role="presentation"><a role="menuitem" tabindex="-1" href="#" class="wn-icon-briefcase">Briefcase</a></li>
<li role="presentation"><a role="menuitem" tabindex="-1" href="#" class="wn-icon-link">Link</a></li>
<li role="presentation"><a role="menuitem" tabindex="-1" href="#" class="wn-icon-tag">Tag</a></li>
<li role="presentation"><a role="menuitem" tabindex="-1" href="#" class="wn-icon-search-minus">Zoom out</a></li>
<li role="presentation"><a role="menuitem" tabindex="-1" href="#" class="wn-icon-briefcase">Briefcase</a></li>
<li role="presentation"><a role="menuitem" tabindex="-1" href="#" class="wn-icon-link">Link</a></li>
<li role="presentation"><a role="menuitem" tabindex="-1" href="#" class="wn-icon-tag">Tag</a></li>
<li role="presentation"><a role="menuitem" tabindex="-1" href="#" class="wn-icon-search-minus">Zoom out</a></li>
<li role="presentation"><a role="menuitem" tabindex="-1" href="#" class="wn-icon-briefcase">Briefcase</a></li>
<li role="presentation"><a role="menuitem" tabindex="-1" href="#" class="wn-icon-link">Link</a></li>
<li role="presentation"><a role="menuitem" tabindex="-1" href="#" class="wn-icon-tag">Tag</a></li>
<li role="presentation"><a role="menuitem" tabindex="-1" href="#" class="wn-icon-search-minus">Zoom out</a></li>
</ul>
</div>

View File

@@ -0,0 +1,54 @@
# Inspector
## Dependencies
- Popover
# Example
<div id="filterExample" class="control-filter" data-control="filterwidget">
<!-- Group -->
<a href="javascript:;" class="filter-scope" data-scope-name="categories">
<span class="filter-label">Categories:</span>
<span class="filter-setting">all</span>
</a>
<!-- Group -->
<a href="javascript:;" class="filter-scope active" data-scope-name="statuses">
<span class="filter-label">Statuses:</span>
<span class="filter-setting">2</span>
</a>
<!-- Checkbox -->
<div class="filter-scope checkbox custom-checkbox" data-scope-name="showActive">
<input type="checkbox" id="chkActive" />
<label for="chkActive">Show active</label>
</div>
</div>
<script>
$('#filterExample').data('filterScopes', {
categories: {
available: [
{ id: 1, name: 'Announcements' },
{ id: 2, name: 'Architecture' },
{ id: 3, name: 'Products' },
{ id: 4, name: 'Services' },
{ id: 5, name: 'Clients' }
]
},
statuses: {
available: [
{ id: 1, name: 'Deleted' },
{ id: 2, name: 'Deployed' },
{ id: 3, name: 'Detailed' }
],
active: [
{ id: 4, name: 'Published' },
{ id: 5, name: 'Draft' }
]
}
})
</script>

View File

@@ -0,0 +1,269 @@
Provides flags of various descriptions using [flag-icon-css](https://github.com/lipis/flag-icon-css).
*Class 'flag-icon flag-icon-{@country}' was merged into flag-{@country}, to support Winter CMS standards.*
## Usage Example
```html
<i class="flag-ad"></i>
<i class="flag-ae"></i>
<i class="flag-af"></i>
<i class="flag-ag"></i>
<i class="flag-ai"></i>
<i class="flag-al"></i>
<i class="flag-am"></i>
<i class="flag-ao"></i>
<i class="flag-aq"></i>
<i class="flag-ar"></i>
<i class="flag-as"></i>
<i class="flag-at"></i>
<i class="flag-au"></i>
<i class="flag-aw"></i>
<i class="flag-ax"></i>
<i class="flag-az"></i>
<i class="flag-ba"></i>
<i class="flag-bb"></i>
<i class="flag-bd"></i>
<i class="flag-be"></i>
<i class="flag-bf"></i>
<i class="flag-bg"></i>
<i class="flag-bh"></i>
<i class="flag-bi"></i>
<i class="flag-bj"></i>
<i class="flag-bl"></i>
<i class="flag-bm"></i>
<i class="flag-bn"></i>
<i class="flag-bo"></i>
<i class="flag-bq"></i>
<i class="flag-br"></i>
<i class="flag-bs"></i>
<i class="flag-bt"></i>
<i class="flag-bv"></i>
<i class="flag-bw"></i>
<i class="flag-by"></i>
<i class="flag-bz"></i>
<i class="flag-ca"></i>
<i class="flag-cc"></i>
<i class="flag-cd"></i>
<i class="flag-cf"></i>
<i class="flag-cg"></i>
<i class="flag-ch"></i>
<i class="flag-ci"></i>
<i class="flag-ck"></i>
<i class="flag-cl"></i>
<i class="flag-cm"></i>
<i class="flag-cn"></i>
<i class="flag-co"></i>
<i class="flag-cr"></i>
<i class="flag-cu"></i>
<i class="flag-cv"></i>
<i class="flag-cw"></i>
<i class="flag-cx"></i>
<i class="flag-cy"></i>
<i class="flag-cz"></i>
<i class="flag-de"></i>
<i class="flag-dj"></i>
<i class="flag-dk"></i>
<i class="flag-dm"></i>
<i class="flag-do"></i>
<i class="flag-dz"></i>
<i class="flag-ec"></i>
<i class="flag-ee"></i>
<i class="flag-eg"></i>
<i class="flag-eh"></i>
<i class="flag-er"></i>
<i class="flag-es"></i>
<i class="flag-et"></i>
<i class="flag-fi"></i>
<i class="flag-fj"></i>
<i class="flag-fk"></i>
<i class="flag-fm"></i>
<i class="flag-fo"></i>
<i class="flag-fr"></i>
<i class="flag-ga"></i>
<i class="flag-gb"></i>
<i class="flag-gd"></i>
<i class="flag-ge"></i>
<i class="flag-gf"></i>
<i class="flag-gg"></i>
<i class="flag-gh"></i>
<i class="flag-gi"></i>
<i class="flag-gl"></i>
<i class="flag-gm"></i>
<i class="flag-gn"></i>
<i class="flag-gp"></i>
<i class="flag-gq"></i>
<i class="flag-gr"></i>
<i class="flag-gs"></i>
<i class="flag-gt"></i>
<i class="flag-gu"></i>
<i class="flag-gw"></i>
<i class="flag-gy"></i>
<i class="flag-hk"></i>
<i class="flag-hm"></i>
<i class="flag-hn"></i>
<i class="flag-hr"></i>
<i class="flag-ht"></i>
<i class="flag-hu"></i>
<i class="flag-id"></i>
<i class="flag-ie"></i>
<i class="flag-il"></i>
<i class="flag-im"></i>
<i class="flag-in"></i>
<i class="flag-io"></i>
<i class="flag-iq"></i>
<i class="flag-ir"></i>
<i class="flag-is"></i>
<i class="flag-it"></i>
<i class="flag-je"></i>
<i class="flag-jm"></i>
<i class="flag-jo"></i>
<i class="flag-jp"></i>
<i class="flag-ke"></i>
<i class="flag-kg"></i>
<i class="flag-kh"></i>
<i class="flag-ki"></i>
<i class="flag-km"></i>
<i class="flag-kn"></i>
<i class="flag-kp"></i>
<i class="flag-kr"></i>
<i class="flag-kw"></i>
<i class="flag-ky"></i>
<i class="flag-kz"></i>
<i class="flag-la"></i>
<i class="flag-lb"></i>
<i class="flag-lc"></i>
<i class="flag-li"></i>
<i class="flag-lk"></i>
<i class="flag-lr"></i>
<i class="flag-ls"></i>
<i class="flag-lt"></i>
<i class="flag-lu"></i>
<i class="flag-lv"></i>
<i class="flag-ly"></i>
<i class="flag-ma"></i>
<i class="flag-mc"></i>
<i class="flag-md"></i>
<i class="flag-me"></i>
<i class="flag-mf"></i>
<i class="flag-mg"></i>
<i class="flag-mh"></i>
<i class="flag-mk"></i>
<i class="flag-ml"></i>
<i class="flag-mm"></i>
<i class="flag-mn"></i>
<i class="flag-mo"></i>
<i class="flag-mp"></i>
<i class="flag-mq"></i>
<i class="flag-mr"></i>
<i class="flag-ms"></i>
<i class="flag-mt"></i>
<i class="flag-mu"></i>
<i class="flag-mv"></i>
<i class="flag-mw"></i>
<i class="flag-mx"></i>
<i class="flag-my"></i>
<i class="flag-mz"></i>
<i class="flag-na"></i>
<i class="flag-nc"></i>
<i class="flag-ne"></i>
<i class="flag-nf"></i>
<i class="flag-ng"></i>
<i class="flag-ni"></i>
<i class="flag-nl"></i>
<i class="flag-no"></i>
<i class="flag-np"></i>
<i class="flag-nr"></i>
<i class="flag-nu"></i>
<i class="flag-nz"></i>
<i class="flag-om"></i>
<i class="flag-pa"></i>
<i class="flag-pe"></i>
<i class="flag-pf"></i>
<i class="flag-pg"></i>
<i class="flag-ph"></i>
<i class="flag-pk"></i>
<i class="flag-pl"></i>
<i class="flag-pm"></i>
<i class="flag-pn"></i>
<i class="flag-pr"></i>
<i class="flag-ps"></i>
<i class="flag-pt"></i>
<i class="flag-pw"></i>
<i class="flag-py"></i>
<i class="flag-qa"></i>
<i class="flag-re"></i>
<i class="flag-ro"></i>
<i class="flag-rs"></i>
<i class="flag-ru"></i>
<i class="flag-rw"></i>
<i class="flag-sa"></i>
<i class="flag-sb"></i>
<i class="flag-sc"></i>
<i class="flag-sd"></i>
<i class="flag-se"></i>
<i class="flag-sg"></i>
<i class="flag-sh"></i>
<i class="flag-si"></i>
<i class="flag-sj"></i>
<i class="flag-sk"></i>
<i class="flag-sl"></i>
<i class="flag-sm"></i>
<i class="flag-sn"></i>
<i class="flag-so"></i>
<i class="flag-sr"></i>
<i class="flag-ss"></i>
<i class="flag-st"></i>
<i class="flag-sv"></i>
<i class="flag-sx"></i>
<i class="flag-sy"></i>
<i class="flag-sz"></i>
<i class="flag-tc"></i>
<i class="flag-td"></i>
<i class="flag-tf"></i>
<i class="flag-tg"></i>
<i class="flag-th"></i>
<i class="flag-tj"></i>
<i class="flag-tk"></i>
<i class="flag-tl"></i>
<i class="flag-tm"></i>
<i class="flag-tn"></i>
<i class="flag-to"></i>
<i class="flag-tr"></i>
<i class="flag-tt"></i>
<i class="flag-tv"></i>
<i class="flag-tw"></i>
<i class="flag-tz"></i>
<i class="flag-ua"></i>
<i class="flag-ug"></i>
<i class="flag-um"></i>
<i class="flag-us"></i>
<i class="flag-uy"></i>
<i class="flag-uz"></i>
<i class="flag-va"></i>
<i class="flag-vc"></i>
<i class="flag-ve"></i>
<i class="flag-vg"></i>
<i class="flag-vi"></i>
<i class="flag-vn"></i>
<i class="flag-vu"></i>
<i class="flag-wf"></i>
<i class="flag-ws"></i>
<i class="flag-ye"></i>
<i class="flag-yt"></i>
<i class="flag-za"></i>
<i class="flag-zm"></i>
<i class="flag-zw"></i>
<i class="flag-es-ct"></i>
<i class="flag-eu"></i>
<i class="flag-gb-eng"></i>
<i class="flag-gb-nir"></i>
<i class="flag-gb-sct"></i>
<i class="flag-gb-wls"></i>
<i class="flag-un"></i>
<p>Squared</p>
<i class="flag-us wn-flag-squared"></i>
```

View File

@@ -0,0 +1,70 @@
## Flash message
Displays a floating flash message on the screen.
### Display onload
```html
<p data-control="flash-message" data-interval="5" class="success">
This message is created from a static element. It will go away in 5 seconds.
</p>
```
<p data-control="flash-message" data-interval="5" class="info">
This message is created from a static element. It will go away in 5 seconds.
</p>
<br />
### Trigger
<p>
<a href="#" class="btn btn-primary" onclick="$.wn.flashMsg({text: 'The record has been successfully saved. This message will go away in 1 second.', 'class': 'success', 'interval': 1}); return false;">
Show Success
</a>
<a href="javascript:;" class="btn btn-danger" onclick="$.wn.flashMsg({text: 'Babam!', 'class': 'error'}); return false;">
Show Error
</a>
<a href="javascript:;" class="btn btn-warning" onclick="$.wn.flashMsg({text: 'Warning! Winter is too good for this world!', 'class': 'warning'}); return false;">
Show Warning
</a>
</p>
### Display static
A flash message can be rendered as a static element by attaching the `static` class. The `data-control` attribute is not needed.
<p class="flash-message static success">
Import completed successfully (success)
</p>
<p class="flash-message static info">
Informative info box is informational (info)
</p>
<p class="flash-message static warning">
Phasers have been set to stun (warning)
</p>
<p class="flash-message static error">
We couldn't help you with that (error)
</p>
### Data attributes
- data-control="flash-message" - enables the flash message plugin
- data-interval="2" - the interval to display the message in seconds, optional. Default: 2
### JavaScript API
```js
$.wn.flashMsg({
'text': 'Record saved.',
'class': 'success',
'interval': 3
})
```

View File

@@ -0,0 +1,180 @@
# Form
## Types
<form class="form-elements" role="form">
<div class="form-group span-left">
<label>First name</label>
<input type="text" name="" value="" class="form-control" />
</div>
<div class="form-group span-right">
<label>Last name</label>
<input type="text" name="" value="" class="form-control" />
</div>
<div class="form-group span-full">
<label>Address</label>
<input type="text" name="" value="" class="form-control" />
</div>
</form>
### Complete example
<!-- Form Elements -->
<form class="form-elements" role="form">
<!-- Text Input (Left) -->
<div class="form-group text-field span-left is-required">
<label>Input Left</label>
<input type="text" name="" value="" class="form-control" />
<p class="help-block">Example below help text here.</p>
</div>
<!-- Text Input (Right) -->
<div class="form-group text-field span-right is-required">
<label>Input Right</label>
<input type="text" name="" value="" class="form-control" />
<p class="help-block">Example below help text here.</p>
</div>
<!-- Text Input (Full) -->
<div class="form-group text-field span-full is-required">
<label>Input Full</label>
<p class="help-block before-field">Example above help text here.</p>
<input type="text" name="" value="" class="form-control" />
</div>
<!-- Drop down -->
<div class="form-group dropdown-field span-left">
<label>Drop Down</label>
<select class="form-control custom-select">
<option selected="selected" value="2">Approved</option>
<option value="3">Deleted</option>
<option value="1">New</option>
</select>
</div>
<!-- Grouped Drop down -->
<div class="form-group dropdown-field span-right">
<label>Grouped Drop Down</label>
<select class="form-control custom-select">
<optgroup label="NFC EAST">
<option>Dallas Cowboys</option>
<option>New York Giants</option>
<option>Philadelphia Eagles</option>
<option>Washington Redskins</option>
</optgroup><optgroup>
</optgroup><optgroup label="NFC NORTH">
<option>Chicago Bears</option>
<option>Detroit Lions</option>
<option>Green Bay Packers</option>
<option>Minnesota Vikings</option>
</optgroup>
<optgroup label="NFC SOUTH">
<option>Atlanta Falcons</option>
<option>Carolina Panthers</option>
<option>New Orleans Saints</option>
<option>Tampa Bay Buccaneers</option>
</optgroup>
<optgroup label="NFC WEST">
<option>Arizona Cardinals</option>
<option>St. Louis Rams</option>
<option>San Francisco 49ers</option>
<option>Seattle Seahawks</option>
</optgroup>
<optgroup label="AFC EAST">
<option>Buffalo Bills</option>
<option>Miami Dolphins</option>
<option>New England Patriots</option>
<option>New York Jets</option>
</optgroup>
<optgroup label="AFC NORTH">
<option>Baltimore Ravens</option>
<option>Cincinnati Bengals</option>
<option>Cleveland Browns</option>
<option>Pittsburgh Steelers</option>
</optgroup>
<optgroup label="AFC SOUTH">
<option>Houston Texans</option>
<option>Indianapolis Colts</option>
<option>Jacksonville Jaguars</option>
<option>Tennessee Titans</option>
</optgroup>
<optgroup label="AFC WEST">
<option>Denver Broncos</option>
<option>Kansas City Chiefs</option>
<option>Oakland Raiders</option>
<option>San Diego Chargers</option>
</optgroup>
</select>
</div>
<!-- Checkbox -->
<div class="form-group checkbox-field span-left is-required">
<div class="checkbox custom-checkbox">
<input name="checkbox" value="1" type="checkbox" id="checkbox_1">
<label for="checkbox_1">Enable Googie Berry Power-up</label>
<p class="help-block">Use this checkbox to enable the Googie Berry power-up specifically for this page. You can configure the Googie Berry power-up on the System Settings and Dashboard page.</p>
</div>
</div>
<!-- Switcher -->
<div class="form-group switch-field span-right">
<div class="field-switch">
<label>Would you like fries with that?</label>
<p class="help-block">Use this checkbox to enable the Googie Berry power-up specifically for this page. You can configure the Googie Berry power-up on the System Settings and Dashboard page.</p>
</div>
<label class="custom-switch">
<input type="checkbox" />
<span><span>On</span><span>Off</span></span>
<a class="slide-button"></a>
</label>
</div>
<!-- Radio List -->
<div class="form-group radio-field span-left is-required">
<label>Radio List</label>
<p class="help-block before-field">Where should you propose to your beautiful girl?</p>
<div class="radio custom-radio">
<input name="radio" value="1" type="radio" id="radio_1">
<label for="radio_1">Paris</label>
<p class="help-block">Do not send new comment notifications.</p>
</div>
<div class="radio custom-radio">
<input checked="checked" name="radio" value="2" type="radio" id="radio_2">
<label for="radio_2">Dubai</label>
<p class="help-block">Send new comment notifications only to post author.</p>
</div>
<div class="radio custom-radio">
<input name="radio" value="3" type="radio" id="radio_3">
<label for="radio_3">New Zealand</label>
<p class="help-block">Notify all users who have permissions to receive blog notifications.</p>
</div>
</div>
<!-- Checkbox List -->
<div class="form-group checkboxlist-field span-right is-required">
<label>Checkbox List</label>
<p class="help-block before-field">What cars would you like in your garage?</p>
<div class="checkbox custom-checkbox">
<input id="checkbox-example1" name="checkbox" value="1" type="checkbox">
<label class="choice" for="checkbox-example1"> Dodge Viper</label>
<p class="help-block">Do not send new comment notifications.</p>
</div>
<div class="checkbox custom-checkbox">
<input checked="checked" id="checkbox-example2" name="checkbox" value="2" type="checkbox">
<label class="choice" for="checkbox-example2"> GM Corvette</label>
<p class="help-block">Send new comment notifications only to post author.</p>
</div>
<div class="checkbox custom-checkbox">
<input id="checkbox-example3" name="checkbox" value="3" type="checkbox">
<label class="choice" for="checkbox-example3"> Porsche Boxter</label>
<p class="help-block">Notify all users who have permissions to receive blog notifications.</p>
</div>
</div>
</form>

View File

@@ -0,0 +1,235 @@
# Foundation
The foundation libraries are the core base of all scripts and controls. The goals of this library are:
- Well structured and readable code.
- Don't leave references to DOM elements.
- Unbind all event handlers.
- Write high-performance code (in cases when it's needed).
That's especially important on pages where users spend much time interacting with the page, like the CMS and Pages sections, but all back-end controls should follow these rules, because we never know when they are used.
## Why it's important to release the memory, DOM references and event handlers
A typical JavaScript control class instance consists of the following parts:
1. JavaScript object representing the control.
1. A reference to the corresponding DOM element. Usually it's the control's root element containing a tree with the control HTML markup.
1. A number of event handlers to handle user's interaction with the control.
If any of that components are not released we have these problems:
1. Non-released JavaScript objects increase the memory footprint. The more memory the application uses, the slower it works. Eventually it could result in a crashed tab or entire browser.
1. Non-released references to DOM elements could result in detached DOM trees. That, in turn, could result in thousands of invisible DOM elements living in a page, increasing the memory footprint and making the application less responsive.
1. Unbound event handlers usually result in non-released DOM elements, which is bad by itself, and also in the code which executes when the user interacts with the application and which should not be executed. That affects the performance.
## This is how to deal with those problems:
1. Remove the JavaScript object - usually by removing the data from the control's root element: `this.$el.removeData('oc.myControl')`
Clean all references to DOM elements. Usually it's done by assigning NULL to corresponding object properties.
1. Watch for any references caught by closures (or - better do not use closures, see below).
1. Unbind event handlers.
Winter Storm UI provides everything we need to meet the goals. Please read on to learn more!
## How to write quality code
OOP approach and prototypes should be used in all places. This approach automatically deals with closures that could retain references to scope variables. Typical class code template:
```js
function ($) { "use strict";
var SomeClass = function() {
this.init()
}
SomeClass.prototype.init = function (){
...
}
}
```
## Basics of writing disposable classes
If a class should be disposable (all UI controls should be disposable), the class should extend `$.wn.foundation.base` class. That class has two useful methods: `proxy(method)` and `dispose()`.
`proxy()` method is an alternative to jQuery's `$.proxy`, but as `$.wn.foundation.base` implements OOP approach, passing this parameter to the method is not required. This method is good for three reasons.
1. It's code is very simple and easily controllable and debuggable.
1. It caches bound functions and doesn't create new function as `$.proxy` does.
1. It automatically removes all cached bound functions when the object is disposed with dispose() method.
`dispose()` method in the base class cleans up bound methods cached by `proxy()` method and provides a common API for disposing objects. All classes that are supposed to do clean-up work, should override that method, do their own clean-up and call the base `dispose()` method.
Example of a disposable class:
```js
+function ($) { "use strict";
var Base = $.wn.foundation.base,
BaseProto = Base.prototype
var SomeDisposableClass = function(element) {
this.$el = $(element)
Base.call(this)
this.init()
}
SomeDisposableClass.prototype = Object.create(BaseProto)
SomeDisposableClass.prototype.constructor = SomeDisposableClass
SomeDisposableClass.prototype.init = function () {
}
SomeDisposableClass.prototype.dispose = function () {
this.$el = null
BaseProto.dispose.call(this)
}
}
```
A couple of important things to note:
1. The class constructor should call Base.call(this).
1. The class prototype should be replaced with a copy of the Base class prototype, and its constructor reference should be restored back to the class constructor. It should be done right after the class constructor and before any method is defined in the class prototype.
## Binding and unbinding events
When binding events, use this.proxy() to make references to event handlers. Always unbind events in dispose() method:
```js
+function ($) { "use strict";
var Base = $.wn.foundation.base,
BaseProto = Base.prototype
var SomeDisposableClass = function(element) {
this.$el = $(element)
Base.call(this)
this.init()
}
[...]
SomeDisposableClass.prototype.init = function () {
this.$el.on('click', this.proxy(this.onClick))
}
SomeDisposableClass.prototype.dispose = function () {
this.$el.off('click', this.proxy(this.onClick))
this.$el = null
BaseProto.dispose.call(this)
}
}
```
## Making disposable controls
UI controls should support two ways of disposing - with calling their `dispose()` method and with invoking the dispose-control handler. Also, disposable controls should mark their corresponding DOM elements as disposable, with Winter foundation API. Example:
```js
+function ($) { "use strict";
var Base = $.wn.foundation.base,
BaseProto = Base.prototype
var SomeDisposableControl = function(element) {
this.$el = $(element)
$.wn.foundation.controlUtils.markDisposable(element)
Base.call(this)
this.init()
}
...
SomeDisposableControl.prototype.init = function () {
this.$el.one('dispose-control', this.proxy(this.dispose))
}
SomeDisposableControl.prototype.dispose = function () {
this.$el.off('dispose-control', this.proxy(this.dispose))
this.$el = null
BaseProto.dispose.call(this)
}
}
```
`$.wn.foundation.controlUtils.markDisposable(element)` call in the constructor adds `data-disposable` attribute to the DOM element, allowing the framework to find all disposable elements in a container and dispose them by calling their dispose-control handler when it's required.
## Full example of a jQuery plugin that creates a disposable control
We already have a boilerplate code for jQuery code. Disposable controls approach just extends it. Don't forget to remove the data associated with controls from their DOM elements.
```js
+function ($) { "use strict";
var Base = $.wn.foundation.base,
BaseProto = Base.prototype
var SomeDisposableControl = function (element, options) {
this.$el = $(element)
this.options = options || {}
$.wn.foundation.controlUtils.markDisposable(element)
Base.call(this)
this.init()
}
SomeDisposableControl.prototype = Object.create(BaseProto)
SomeDisposableControl.prototype.constructor = SomeDisposableControl
SomeDisposableControl.prototype.init = function() {
this.$el.on('click', this.proxy(this.onClick))
this.$el.one('dispose-control', this.proxy(this.dispose))
}
SomeDisposableControl.prototype.dispose = function() {
this.$el.off('click', this.proxy(this.onClick))
this.$el.off('dispose-control', this.proxy(this.dispose))
this.$el.removeData('oc.someDisposableControl')
this.$el = null
// In some cases options could contain callbacks,
// so it's better to clean them up too.
this.options = null
BaseProto.dispose.call(this)
}
SomeDisposableControl.DEFAULTS = {
someParam: null
}
// PLUGIN DEFINITION
// ============================
var old = $.fn.someDisposableControl
$.fn.someDisposableControl = function (option) {
var args = Array.prototype.slice.call(arguments, 1), items, result
items = this.each(function () {
var $this = $(this)
var data = $this.data('oc.someDisposableControl')
var options = $.extend({}, SomeDisposableControl.DEFAULTS, $this.data(), typeof option == 'object' && option)
if (!data) $this.data('oc.someDisposableControl', (data = new SomeDisposableControl(this, options)))
if (typeof option == 'string') result = data[option].apply(data, args)
if (typeof result != 'undefined') return false
})
return result ? result : items
}
$.fn.someDisposableControl.Constructor = SomeDisposableControl
$.fn.someDisposableControl.noConflict = function () {
$.fn.someDisposableControl = old
return this
}
// Add this only if required
$(document).render(function (){
$('[data-some-disposable-control]').someDisposableControl()
})
}(window.jQuery);
```

View File

@@ -0,0 +1,146 @@
# Icon library (Font Awesome 6)
Winter includes the [Font Awesome 6 Free](https://fontawesome.com/) icon set by default, allowing people to use over 1,500 free design icons and nearly 500 branding icons within the Backend or the CMS. We have also included compatibility with Font Awesome 4 classes for older plugins and themes.
For more information on the Font Awesome library, or to search through the available icons, visit the [Font Awesome website](https://fontawesome.com/search?m=free).
## Browsing the icons
You may browse the available icons on the Font Awesome website at the following URL:
https://fontawesome.com/search?m=free
Please note that we only include the free icons and brands.
## Using the icons
You may place icons just about anywhere by placing an inline tag (such as a `<i>` or `<span>` tag) and setting the class to the icon you wish to use:
```html
<i class="icon-camera-retro"></i> icon-camera-retro
<span class="icon-flag-checkered"></span> wn-icon-flag-checkered
```
<div class="frame" style="font-size: 22px;">
<i class="icon-camera-retro"></i> icon-camera-retro
<br />
<span class="icon-flag-checkered"></span> wn-icon-flag-checkered
</div>
Using the `wn-` prefix will allow you to prefix content inside the given tag with an icon:
```html
<i class="wn-icon-star">You're a star!</i>
<strong class="wn-icon-snowflake">Winter is coming.</strong>
```
<div class="frame" style="font-size: 22px;">
<i class="wn-icon-star">You're a star!</i>
<br>
<strong class="wn-icon-snowflake">Winter is coming.</strong>
</div>
You may also opt to use the standard Font Awesome classes as well:
```html
<i class="fas fa-star">You're a star!</i>
<strong class="fas fa-snowflake">Winter is coming.</strong>
```
<div class="frame" style="font-size: 22px;">
<i class="fas fa-star">You're a star!</i>
<br>
<strong class="fas fa-snowflake">Winter is coming.</strong>
</div>
### Icon styles
As with Font Awesome 6, Winter also includes three styles of icon: solid, regular and brand. By default, the icons in Winter use the solid style, which has the full set of free icons available.
To use a regular style icon, which is less pronounced but also has much less available icons, you may include the `icon-regular` class alongside your icon class. For brands, you may include the `icon-brand` class.
```html
<i class="icon-star"></i> Solid
<i class="icon-regular icon-star"></i> Regular
```
<div class="frame" style="font-size: 22px;">
<i class="icon-star"></i> Solid
<br>
<i class="icon-regular icon-star"></i> Regular
</div>
We also provide support for the Font Awesome style classes as well: `fas` for solid, `far` for regular and `fab` for brand.
### Icon sizes
Winter supports multiple sizing classes to control the size of the icons.
You may size by 1-10 times the regular size of icons.
```html
<i class="icon-camera-retro icon-10x"></i> icon-10x
<i class="icon-camera-retro icon-9x"></i> icon-9x
<i class="icon-camera-retro icon-8x"></i> icon-8x
<i class="icon-camera-retro icon-7x"></i> icon-7x
<i class="icon-camera-retro icon-6x"></i> icon-6x
<i class="icon-camera-retro icon-5x"></i> icon-5x
<i class="icon-camera-retro icon-4x"></i> icon-4x
<i class="icon-camera-retro icon-3x"></i> icon-3x
<i class="icon-camera-retro icon-2x"></i> icon-2x
<i class="icon-camera-retro icon-1x"></i> icon-1x
```
We also provide more classes that match common sizing prefixes in CSS frameworks such as `sm`, `lg`, etc.
```html
<i class="icon-camera-retro icon-2xs"></i> icon-2xs
<i class="icon-camera-retro icon-xs"></i> icon-xs
<i class="icon-camera-retro icon-sm"></i> icon-sm
<i class="icon-camera-retro icon-lg"></i> icon-lg
<i class="icon-camera-retro icon-xl"></i> icon-xl
<i class="icon-camera-retro icon-2xl"></i> icon-2xl
```
### Icon list items
You can apply icons to lists, allowing you to use the icon as the list item prefix as opposed to a standard circle.
You must include the `icon-ul` class to a `<ul>` tag, and then the `icon-li` class to all `<li>` items within to take advantage of this feature.
```html
<ul class="icon-ul">
<li class="icon-li icon-battery-0">Empty</li>
<li class="icon-li icon-battery">Low</li>
<li class="icon-li icon-battery-half">Charging</li>
<li class="icon-li icon-battery-full">Full</li>
</ul>
```
### Icon buttons
Feel free to use them alongside your buttons.
```html
<a class="btn btn-default wn-icon-refresh" href="#">
Refresh
</a>
<a class="btn btn-success wn-icon-shopping" href="#">
Checkout
</a>
<a class="btn btn-primary wn-icon-comment" href="#">
Comment
</a>
<a class="btn btn-danger wn-icon-trash" href="#">
Delete
</a>
<a class="btn btn-default wn-icon-cog" href="#">
Settings
</a>
<a class="btn btn-info wn-icon-info" href="#">
More Info
</a>
```

View File

@@ -0,0 +1,29 @@
# Input Hotkey API
Allows keyboard shortcuts (hotkeys) to be bound to an element's click event.
# Example
<button
class="btn btn-default"
data-hotkey="b"
onclick="alert('B is for Banana!')">
Press "B" on your keyboard
</button>
<button
class="btn btn-default"
data-hotkey="shift+r"
onclick="confirm('Shift gears...?')">
Press "Shift + R" on your keyboard
</button>
## Javascript API
If you use a selector other than a button or a link, you will need to add the `hotkeyVisible` property to the hotkey config.
$('html').hotKey({
hotkey: 'ctrl+s, cmd+s',
hotkeyVisible: false,
callback: doSomething
});

View File

@@ -0,0 +1,60 @@
# Input Monitoring
This will monitor the user input for unsaved changes and show a confirmation box if the user attempts to leave the page. The script adds the "oc-data-changed" class to the form element when the form data is changed.
```html
<form
data-change-monitor
data-window-close-confirm="There is unsaved data"
>
...
</form>
```
### Example
Click the "Mark changed" button and "Reload page".
<form
data-window-close-confirm="There is unsaved data"
data-change-monitor>
<button type="button" onclick="$(this).trigger('change')">
Mark changed
</button>
<button type="button" onclick="$(this).trigger('unchange.oc.changeMonitor')">
Mark saved
</button>
<hr />
<button type="button" onclick="window.location.reload()">
Reload page
</button>
</form>
## Supported data attributes
- data-change-monitor - enables the plugin form a form
- data-window-close-confirm - confirmation message to show when a browser window is closing and there is unsaved data
## Supported events
- change - marks the form data as "changed". The event can be triggered on any element within a form or on a form itself.
- unchange.oc.changeMonitor - marks the form data as "unchanged". The event can be triggered on any element within a form or on a form itself.
- pause.oc.changeMonitor - temporary pauses the change monitoring. The event can be triggered on any element within a form or on a form itself.
- resume.oc.changeMonitor - resumes the change monitoring. The event can be triggered on any element within a form or on a form itself.
## Triggered events
- changed.oc.changeMonitor - triggered when the form data changes.
- unchanged.oc.changeMonitor - triggered when the form data unchanges.
- ready.oc.changeMonitor triggered when the change monitor instance finishes initialization.
## JavaScript API
```js
$('#form').changeMonitor()
```

View File

@@ -0,0 +1,11 @@
# Input Preset API
Scripts that manage user input events.
# Example
<input type="text" id="presetExample1" placeholder="Type something" />
<input type="text"
data-input-preset="#presetExample1"
placeholder="Watch here"
disabled />

View File

@@ -0,0 +1,85 @@
# Input Trigger API
The API allows to change elements' visibility or status (enabled/disabled) basing on other elements' statuses. Example: enable a button if any checkbox inside another element is checked.
## Example
### Checked condition
<input type="checkbox" id="triggerChk1" />
<button class="btn disabled"
data-trigger-action="enable"
data-trigger="#triggerChk1"
data-trigger-condition="checked">
Check the checkbox
</button>
### Value condition
<p>
<input
type="text"
id="triggerTxt1"
value=""
onkeyup="$(this).trigger('change')"
placeholder="Enter 'foo' or 'bar' here"
class="form-control" />
</p>
<div
class="callout callout-success"
data-trigger-action="show"
data-trigger="#triggerTxt1"
data-trigger-condition="value[foo][bar]">
<div class="content">
Passphrase is valid!
</div>
</div>
## Supported data attributes
- data-trigger-action, values: show, hide, enable, disable, empty
- data-trigger: a CSS selector for elements that trigger the action (checkboxes)
- data-trigger-condition, values:
- checked: determines the condition the elements specified in the data-trigger should satisfy in order the condition to be considered as "true".
- unchecked: inverse condition of "checked".
- value[somevalue]: determines if the value of data-trigger equals the specified value (somevalue) the condition is considered "true".
- data-trigger-closest-parent: optional, specifies a CSS selector for a closest common parent for the source and destination input elements.
Example code:
```html
<input type="button" class="btn disabled"
data-trigger-action="enable"
data-trigger="#cblist input[type=checkbox]"
data-trigger-condition="checked" ... >
```
Multiple actions are supported:
```html
data-trigger-action="hide|empty"
```
Multie value conditions are supported:
```html
data-trigger-condition="value[foo][bar]"
```
### Supported events
- oc.triggerOn.update - triggers the update. Trigger this event on the element the plugin is bound to to force it to check the condition and update itself. This is useful when the page content is updated with AJAX.
- oc.triggerOn.afterUpdate - triggered after the element is updated
### JavaScript API
```html
$('#mybutton').triggerOn({
triggerCondition: 'checked',
trigger: '#cblist input[type=checkbox]',
triggerAction: 'enable'
})
```

View File

@@ -0,0 +1,724 @@
# Inspector control
Inspector is a visual configuration tool that is used in several places of Winter back-end. The most known usage of Inspector is the CMS components configuration feature, but Inspector is not limited with the CMS. In fact, it's a universal tool that can be used with any element on a back-end page.
The Inspector loads the configuration schema from an inspectable element, builds the user interface, and writes values entered by users back to the inspectable element. The first version of Inspector was supporting only a few scalar value types - strings and Booleans, without an option to edit any complex data.
The current version of Inspector allows to edit any imaginable data structures, including cases where users create enumerable data elements right in the Inspector interface.
This section describes the client-side Inspector API without going into details about the back-end usage of the data Inspector generates. Inspector accepts the configuration schema in JSON format and generates values in JSON format as well. Providing the configuration and interpreting the generated values is up to developers. For example, the CMS module uses information returned from component's defineProperties() method to generate the configuration JSON string and converts JSON values generated by Inspector to the components configuration in CMS templates. In this document we are focusing only on the JSON format.
## Configuring inspectable elements
Clicking an inspectable element displays Inspector for that element. Any HTML element could be made inspectable by adding data attributes to it. The required attributes are:
* `data-inspectable` - indicates that Inspector should be created when the element is clicked.
* `data-inspector-title` - sets the Inspector popup title.
* `data-inspector-config` - contains the Inspector configuration JSON string. If this attribute is not specified, the configuration is loaded from the server, see the [Dynamic configuration and dynamic items](#dynamic-configuration-and-dynamic-items) section below.
Inspectable elements should also contain a hidden input element used by Inspector for reading and writing values. The input element should be marked with the `data-inspector-values` data attribute.
Example inspectable element markup:
```html
<div
data-inspectable
data-inspector-title="Some inspectable element"
data-inspector-description="Some description">
<input
data-inspector-values
type="hidden"
value="JSON"/>
</div>
```
### Optional data attributes
There are several optional data attributes and features that could be defined in an inspectable element or in elements around it:
* `data-inspector-offset` - sets offset, in pixels, for the Inspector popup.
* `data-inspector-offset-x` - sets horizontal offset, in pixels, for the Inspector popup.
* `data-inspector-offset-y` - sets vertical offset, in pixels, for the Inspector popup.
* `data-inspector-placement` - sets defines placement for the Inspector popup, optional. If omitted, Inspector evaluates a placement automatically. Supported values: top, bottom, left, top.
* `data-inspector-fallback-placement` - sets less preferable placement for the Inspector popup, optional. This value is used if Inspector can't use the placement specified in data-inspector-placement. Supported values: top, bottom, left, top.
* `data-inspector-external-parameters` - if this attribute exists in any parent element of the inspectable element, the external parameters editors will be enabled in Inspector (unless property-specific rules cancel the external editor).
### Dynamic configuration and dynamic items
In case if the `data-inspector-config` attribute is missing in the inspectable element Inspector tries to load its configuration from the server. An important note - there should be a FORM element wrapping inspectable elements in order to use any dynamic features of Inspector.
The AJAX request used for loading the configuration from the server is named `onGetInspectorConfiguration`. The handler should be defined in the back-end controller and should return an array containing the Inspector configuration (in the PHP equivalent of the JSON configuration structure described later in this section), inspector title and description. Example of a server-side AJAX dynamic configuration request handler:
```php
public function onGetInspectorConfiguration()
{
// Load and use some values from the posted form
//
$someValue = Request::input('someValue');
... do some processing ...
return [
'configuration' => [
'properties' => [list of properties],
'title' => 'Inspector title',
'description' => 'Inspector description'
]
];
}
```
Some Inspector editors - (drop-down, set, autocomplete) support static and dynamic options. Dynamic options are requested from the server, rather than being defined in the configuration JSON string. For using this feature, the inspectable element must have the `data-inspector-class` attribute defined. The attribute value should contain a name of a PHP class corresponding to the inspectable element.
The server-side controller should use the `Backend\Traits\InspectableContainer` trait in order to provide the dynamic options loading. The inspectable PHP class (specified with `data-inspector-class`) must either have a method `get[Property]Options()`, where the [Property] part corresponds the name of the dynamic property, or `getPropertyOptions($propertyName)` method that is more universal and accepts the property name as a parameter. The methods should return the `options` array containing associative arrays with keys `option` and `value`. Example:
```php
public function getContextOptions()
{
$optionsArray = [];
$optionsArray[] = ['value' => 'create', 'title' => 'Create'];
$optionsArray[] = ['value' => 'update', 'title' => 'Update'];
$optionsArray[] = ['value' => 'delete', 'title' => 'Delete'];
return [
'options' => $optionsArray
];
}
```
### Container and popups
By default Inspector is displayed in a popup, but there's an option to display it right on the page, in a container element. To enable this option, all inspectable elements should be wrapped into another element with `data-inspector-container` attribute. The attribute value should be a CSS selector pointing to an element inside the wrapper. Example:
```html
<div data-inspector-container=".inspector-container">
<div class="inspector-container"></div>
<div data-inspectable ... ...>
<div data-inspectable ... ...>
</div>
```
The inner element will act as host element for Inspector when an inspectable element is clicked. The element should have the `inspector-container` class and can be optionally marked with `data-inspector-scrollable` attribute to make the Inspector scrollable. For the scrolling feature, the container element should have height defined explicitly.
When the container is used, Inspector is still displayed in a popup by default, but users can click an icon in the Inspector header to move it to the container.
## Data schema configuration
Inspector configuration, defined with `data-inspector-config` attribute or loaded from the server, should be an array containing a list of property definition. All examples in this section use JSON format. Below is an example of a configuration for two properties:
```json
[
{
"property": "firstName",
"title": "First name",
"type": "string"
},
{
"property": "lastName",
"title": "Last name",
"type": "string"
}
]
```
This configuration creates two text fields with titles "First name" and "Last name". When the data is saved back to the inspectable element (to the `data-inspector-values` hidden input element), it would have the following format:
```json
{"firstName":"John", "lastName":"Smith"}
```
Each property should have attributes `property`, `title` and `type`. The `type` attribute defines a type of an editor that should be created for the property. The supported editors are described further.
Other attributes supported by all (or most of the) property types are:
* `description` - description string, which is available in a tooltip displayed when a user overs the 'i' icon in the property editor.
* `group` - allows to group multiple properties. The attribute should contain a group name. Groups could be collapsed by users, making the Inspector interface less cluttered.
* `showExternalParam` - enables the inspector parameter editor for the property. External parameters are currently used only by the CMS. Note that some property types do not support external property editors. See also `data-inspector-external-parameters` attribute described above.
* `placeholder` - text to display in the editor if property value is empty.
* `validation` - validation configuration. See the complete validation description below.
* `default` - default property value. The property value format depends on the property type - for the `string` type it's an array, for `stringList` type it's an array of strings. See more details below.
All other configuration properties are specific for different property types.
### String editor
String editor allows entering a single line of a text and represented with a simple input text field. The editor doesn't have any specific parameters. The optional `default` parameter for the editor should contain a string.
```json
{
"property": "firstName",
"title": "First name",
"type": "string",
"default": "John"
}
```
The editor generates string values:
```json
{"firstName":"Sam"}
```
### Text editor
Text editor allows entering multi-line long text values in a popup window. The editor doesn't have any specific parameters. The optional `default` parameter for the editor should contain a string.
```json
{
"property": "description",
"title": "Description",
"type": "text",
"default": "This is a default description"
}
```
The editor generates string values:
```json
{"description":"This is a description"}
```
### String list editor
Allows users to enter lists of strings. The editor opens in a popup window and displays a text area. Each line of text represents an element in the result array. The optional `default` parameter should contain an array of strings. Example:
```json
{
"property": "items",
"title": "Items"
"type": "stringList",
"default": ["String 1", "String 2"]
}
```
A value generated by the editor is an array of strings, for example:
```json
{"items":["String 1","String 2","String 3"]}
```
### Autocomplete editor
This editor works like the `string` editor, but includes the autocomplete feature. Autocompletion options can be specified statically, with the `items` parameter or loaded dynamically. Example with static options:
```json
{
"property": "condition",
"title": "Condition"
"type": "autocomplete",
"items": {"start": "Start", "end": "End"}
}
```
The items are specified as a key-value object. The `items` parameter is optional, if it's not provided, the items will be loaded from the server - see [Dynamic configuration and dynamic items](#dynamic-configuration-and-dynamic-items) section above.
Values generated by the editor are strings. Example:
```json
{"condition":"start"}
```
Fields of this type do not support external property editors.
### Checkbox editor
Properties of this type are represented with a checkbox in the Inspector UI. This property doesn't have any special parameters. The `default` parameter, if specified, should contain a Boolean value or string values "true", "false", "1", "0". Example:
```json
{
"property": "enabled",
"title": "Enabled",
"type": "checkbox",
"default": true
}
```
Values generated by the editor are 0 (unchecked) or 1 (checked). Example:
```json
{"enabled":1}
```
### Dropdown editor
Displays a drop-down list. Options for the drop-down list can be specified statically with the `options` attribute or loaded from the server dynamically. Example:
```json
{
"property": "action",
"title": "Action",
"type": "dropdown",
"options": {
"show": "Show",
"hide": "Hide",
"enable": "Enable",
"disable": "Disable",
"empty": "Empty"
}
}
```
The `options` attribute should be a key-value object. If the attribute is not specified, Inspector will try to load options from the server - see [Dynamic configuration and dynamic items](#dynamic-configuration-and-dynamic-items) section above.
The editor generates a string value corresponding to the selected option, for example:
```json
{"action":"hide"}
```
### Dictionary editor
Dictionary editor allows to create key-value pairs with a simple user interface consisting of a table with two columns. The `default` parameter, if specified, should contain a key-value object. Example:
```json
{
"property": "options",
"title": "Options",
"type": "dictionary",
"default": {"option1": "Option 1"}
}
```
The editor generates an object value, for example:
```json
{"options":{"option1":"Option 1","option2":"Option 2"}}
```
The dictionary editor supports validation for the entire set (`required` and `length` validators) and for keys and values separately. See the [validation description](#defining-the-validation-rules) further in this document. The `validationKey` and `validationValue` define validation for keys and values, for example:
```json
{
"property": "options",
"title": "Options",
"type": "dictionary",
"validation": {
"required": {
"message": "Please create options"
},
"length": {
"min": {
"value": 2,
"message": "Create at least two options."
}
}
},
"validationKey": {
"regex": {
"pattern": "^[a-z]+$",
"message": "Keys can contain only lowercase Latin letters"
}
},
"validationValue": {
"regex": {
"pattern": "^[a-zA-Z0-9]+$",
"message": "Values can contain only Latin letters and digits"
}
}
}
```
### Object editor
Allows to define an object with specific properties editable by users. Object properties are specified with the `properties` attribute. The value of the attribute is an array, which has exactly the same structure as the Inspector properties array.
```json
{
"property": "address",
"title": "Address",
"type": "object",
"properties": [
{
"property": "streetAddress",
"title": "Street address",
"type": "string"
},
{
"property": "city",
"title": "City",
"type": "string"
},
{
"property": "country",
"title": "Country",
"type": "dropdown",
"options": {"us": "US", "ca": "Canada"}
}
]
}
```
The example above creates an object with three properties. Two of them are displayed as text fields, and the third as a drop-down.
Object editor values are objects. Example:
```json
{
"address": {
"streetAddress":"321-210 Second ave",
"city":"Springfield",
"country":"us"
}
}
```
The object properties can be of any type supported by Inspector, including other objects.
There's a way to exclude an object from Inspector values completely, if one of the object fields is empty. The field is identified with `ignoreIfPropertyEmpty` parameter. For example:
```json
{
"property": "address",
"title": "Address",
"type": "object",
"ignoreIfPropertyEmpty": "title",
"properties": [
{
"property": "streetAddress",
"title": "Street address",
"type": "string"
},
{
"property": "city",
"title": "City",
"type": "string"
}
]
}
```
In the example above, if the street address is not specified, the object ("address") will be completely removed from the Inspector output. If there are any validation rules defined on other object properties and the required property is empty, those rules will be ignored.
A `default` value for the editor, if specified, should be an object with the same properties as defined in the `properties` configuration parameter.
Object editors do not support the external property editor feature.
### Object list editor
The object list editor allows users to create multiple objects with a pre-defined structure. For example, it could be used for creating a list of person, where each person has a name and address.
The properties of objects that can be created with the editor are defined with `itemProperties` parameter. The parameter should contain an array of properties, similar to Inspector configuration array. Another required parameter is `titleProperty`, which identifies a property that should be used as a title in Inspector UI. Example configuration:
```json
{
"property": "people",
"title": "People",
"type": "objectList",
"titleProperty": "fullName",
"itemProperties": [
{
"property": "fullName",
"title": "Full name",
"type": "string"
},
{
"property": "address",
"title": "Address",
"type": "string"
}
]
}
```
The array of properties defined with `itemProperties` supports all property types.
The Object List editor type doesn't support default values.
By default the value created by the editor of this type is a non-associative array:
```json
{
"people":[
{"fullName":"John Smith","address":"Palo Alto"},
{"fullName":"Bart Simpson","address":"Springfield"}
]
}
```
If the result value should be an associative array (object), use the `keyProperty` configuration option. The option value should refer to a property that should be used as a key. The key property can use only the string or drop-down editors, its value should be unique and cannot be empty. Example:
```json
{
"property": "people",
"title": "People",
"type": "objectList",
"titleProperty": "fullName",
"keyProperty": "login",
"itemProperties": [
{
"property": "fullName",
"title": "Full name",
"type": "string"
},
{
"property": "login",
"title": "Login",
"type": "string"
},
{
"property": "address",
"title": "Address",
"type": "string"
}
]
}
```
The `login` property in the example above will be used as a key in the result value:
```json
{
"people":{
"john":{"fullName":"John Smith","address":"Palo Alto"},
"bart":{"fullName":"Bart Simpson","address":"Springfield"}
}
}
```
### Set editor
The set editor allows users to select multiple predefined options with checkboxes. Set items can be specified statically with the configuration, using the `items` parameter, or loaded dynamically. Example with static items definition:
```json
{
"property": "context",
"title": "Context",
"type": "set",
"items": {
"create": "Create",
"update": "Update",
"preview": "Preview"
},
"default": ["create", "update"]
}
```
The `items` attribute should be a key-value object. If the attribute is not specified, Inspector will try to load options from the server - see [Dynamic configuration and dynamic items](#dynamic-configuration-and-dynamic-items) section above.
The `default` parameter, if specified, should be an array listing item keys selected by default.
Set editors do not support the external property editor feature.
## Defining the validation rules
Inspector support several validation rules that can be applied to properties. Validation rules can be applied to top-level properties as well as to internal property definitions of object and object list editors. There are two ways to define validation rules - the legacy syntax and the new syntax.
The legacy syntax is supported for the backwards compatibility with existing CMS components definitions. This syntax will always be supported, but it's limited, and cannot be mixed with the new syntax. Example of the legacy syntax:
```json
{
"property": "name",
"title": "Name",
"type": "string",
"required": true,
"validationPattern": "^[a-zA-Z]+$"
"validationMessage": "The Name field is required and can contain only Latin letters.",
}
```
The legacy syntax supports only two validation rules - required and regular expression. The new syntax is much more flexible and extendable:
```json
{
"property": "name",
"title": "Name",
"type": "string",
"validation": {
"required": {
"message": "The Name field is required"
},
"regex": {
"message": "The Name field can contain only Latin letters.",
"pattern": "^[a-zA-Z]+$"
}
}
}
```
The key value in the `validation` object refers to a validator (see below). Validators are configured with objects, which properties depend on a validator. One property - `message` is common for all validators.
### required validator
Checks if a value is not empty. The validator can be used with any editor, including complex editors (sets, dictionaries, object lists, etc.). Example:
```json
{
"property": "name",
"title": "Name",
"type": "string",
"validation": {
"required": {
"message": "The Name field is required"
}
}
}
```
### regex validator
Validates string values with a regular expression. The validator can be use only with string-typed editors. Example:
```json
{
"property": "name",
"title": "Name",
"type": "string",
"validation": {
"regex": {
"message": "The Name field can contain only Latin letters",
"pattern": "^[a-z]+$",
"modifiers": "i"
}
}
}
```
The regular expression is specified with the required `pattern` parameter. The `modifiers` parameter is optional and can be used for setting regular expression modifiers.
### integer validator
Checks if the value is integer and can optionally validate if the value is within a specific interval. The validator can be used only with string-typed editors. Example:
```json
{
"property": "numOfColumns",
"title": "Number of Columns",
"type": "string",
"validation": {
"integer": {
"message": "The Number of Columns field should contain an integer value",
"allowNegative": true,
"min": {
"value": -10,
"message": "The number of columns should not be less than -10."
},
"max": {
"value": 10,
"message": "The number of columns should not be greater than 10."
}
}
}
}
```
Supported parameters:
* `allowNegative` - optional, determines if negative values are allowed. By default negative values are not allowed.
* `min` - optional object, defines the minimum allowed value and error message. Object fields:
* `value` - defines the minimum value.
* `message` - optional, defines the error message.
* `max` - optional object, defines the maximum allowed value and error message. Object fields:
* `value` - defines the maximum value.
* `message` - optional, defines the error message.
### float validator
Checks if the value is a floating point number. The parameters for this validator match the parameters of the **integer** validator described above. Example:
```json
{
"property": "amount",
"title": "Amount",
"type": "string",
"validation": {
"float": {
"message": "The Amount field should contain a positive floating point value."
}
}
}
```
Valid floating point number formats:
* 10
* 10.302
* -10 (if `allowNegative` is `true`)
* -10.84 (if `allowNegative` is `true`)
### length validator
Checks if a string, array or object is not shorter or longer than specified values. This validator can work with the string, text, set, string list, dictionary and object list editors. In multiple-value editors (set, string list, dictionary and object list) it validates the number of items created in the editor.
> **Note**: the `length` validator doesn't validate empty values. For example, if it's applied to a set editor, and the set is empty, the validation will pass regardless of the `min` and `max` parameter values. Use the `required` validator together with the `length` validator to make sure that the value is not empty before the length validation is applied.
```json
{
"property": "name",
"title": "Name",
"type": "string",
"validation": {
"length": {
"min": {
"value": 2,
"message": "The name should not be shorter than two letters."
},
"max": {
"value": 10,
"message": "name should not be longer than 10 letters."
}
}
}
}
```
Supported parameters:
* `min` - optional object, defines the minimum allowed length and error message. Object fields:
* `value` - defines the minimum value.
* `message` - optional, defines the error message.
* `max` - optional object, defines the maximum allowed length and error message. Object fields:
* `value` - defines the maximum value.
* `message` - optional, defines the error message.
## Inspector events
Inspector triggers several events on the inspectable elements.
### change
The `change` event is triggered after Inspector applies updated values to the inspectable element. The event is triggered only if the user has changed values in the Inspector UI.
### showing.oc.inspector
The `showing.oc.inspector` event is triggered before Inspector is displayed. The event handler can optionally stop the process with calling `ev.isDefaultPrevented()`. Example - prevent Inspector showing:
```js
$(document).on('showing.oc.inspector', 'div[data-inspectable]', function(ev, data){
ev.preventDefault()
})
```
The handler could perform any required processing, even asynchronous, and then call the callback function passed to the handler, to continue showing the Inspector. In this case the handler should call `ev.stopPropagation()` method to stop the default Inspector initialization. Example - continue showing after some processing:
```js
$(document).on('showing.oc.inspector', 'div[data-inspectable]', function(ev, data){
ev.stopPropagation()
// The callback function can be called asynchronously
data.callback()
})
```
### hiding.oc.inspector
The `hiding.oc.inspector` is called before Inspector hiding process starts. The handler can stop the hiding with calling `ev.preventDefault()`. Example:
```js
$(document).on('hiding.oc.inspector', 'div[data-inspectable]', function(ev, data){
if (!confirm('Allow hiding?')) {
ev.preventDefault()
}
})
```
The values entered in Inspector are available through the `values` element of the second handler argument:
```js
$(document).on('hiding.oc.inspector', 'div[data-inspectable]', function(ev, data){
console.log(data.values)
})
```
### hidden.oc.inspector
The `hidden.oc.inspector` is triggered after Inspector is hidden.

View File

@@ -0,0 +1,336 @@
### Basic example
<div class="control-list">
<table class="table data">
<thead>
<tr>
<th class="sort-desc"><a href="/">Title</a></th>
<th class="active sort-asc"><a href="/">Created</a></th>
<th><span>Categories</span></th>
<th><span>Updated</span></th>
<th class="list-setup"><a href="/" title="List options"></a></th>
</tr>
</thead>
<tbody>
<tr>
<td>Welcome to Winter</td>
<td>Oct 01, 2013</td>
<td>News</td>
<td>Oct 01, 2013</td>
<td>&nbsp;</td>
</tr>
</tbody>
</table>
</div>
### Complete example
<div class="control-list">
<table class="table data" data-control="rowlink">
<thead>
<tr>
<th class="list-checkbox">
<div class="checkbox custom-checkbox nolabel">
<input type="checkbox" id="checkboxAll" />
<label for="checkboxAll"></label>
</div>
</th>
<th class="sort-desc"><a href="/">Title</a></th>
<th class="active sort-asc"><a href="/">Created</a></th>
<th class="sort-desc"><a href="/">Author</a></th>
<th><span>Categories</span></th>
<th><span>Published</span></th>
<th><span>Updated</span></th>
<th class="list-setup"><a href="/" title="List options"></a></th>
</tr>
</thead>
<tbody>
<tr>
<td class="list-checkbox nolink">
<div class="checkbox custom-checkbox nolabel">
<input id="checkbox_1" type="checkbox" />
<label for="checkbox_1">Check</label>
</div>
</td>
<td><a href="/">Welcome to Winter</a></td>
<td>Oct 01, 2013</td>
<td>Adam Person</td>
<td>News</td>
<td>Oct 01, 2013</td>
<td>Oct 01, 2013</td>
<td>&nbsp;</td>
</tr>
<tr class="active">
<td class="list-checkbox nolink">
<div class="checkbox custom-checkbox nolabel">
<input id="checkbox_2" type="checkbox" checked="checked" /><label for="checkbox_2">Check The marketplace is open!</label>
</div>
</td>
<td><a href="/">The marketplace is open!</a></td>
<td>Oct 15, 2013</td>
<td>Sam Georges</td>
<td>Features</td>
<td>Oct 16, 2013</td>
<td>Oct 16, 2013</td>
<td>&nbsp;</td>
</tr>
<tr>
<td class="list-checkbox nolink">
<div class="checkbox custom-checkbox nolabel">
<input id="checkbox_3" type="checkbox" />
<label for="checkbox_3">Check Welcome to the Builder!</label>
</div>
</td>
<td><a href="/">Welcome to the Builder!</a></td>
<td>Oct 21, 2013</td>
<td>Alexey Bobkov</td>
<td>News, Features</td>
<td>Oct 21, 2013</td>
<td>Oct 21, 2013</td>
<td>&nbsp;</td>
</tr>
<tr>
<td class="list-checkbox nolink">
<div class="checkbox custom-checkbox nolabel">
<input id="checkbox_4" type="checkbox" />
<label for="checkbox_4">Check Components explained</label>
</div>
</td>
<td><a href="/">Components explained</a></td>
<td>Nov 12, 2013</td>
<td>Alexey Bobkov</td>
<td>Tutorials</td>
<td>Nov 12, 2013</td>
<td>Nov 12, 2013</td>
<td>&nbsp;</td>
</tr>
<tr>
<td class="list-checkbox nolink">
<div class="checkbox custom-checkbox nolabel">
<input id="checkbox_5" type="checkbox" />
<label for="checkbox_5">Check Creating a module in 90 seconds</label>
</div>
</td>
<td><a href="/">Creating a module in 90 seconds</a></td>
<td>Nov 15, 2013</td>
<td>Sam Georges</td>
<td>Tutorials</td>
<td>Nov 15, 2013</td>
<td>Nov 15, 2013</td>
<td>&nbsp;</td>
</tr>
</body>
</table>
<div class="list-footer">
<div class="list-pagination">
<div class="control-pagination">
<span class="page-iteration">1-5 of 20</span>
<a href="#" class="page-back" title="Previous page"></a><a href="#" class="page-next" title="Next page"></a>
</div>
</div>
</div>
</div>
### Empty list
Use the `no-data` class to display a list that contains no records.
<div class="control-list">
<table class="table data">
<thead>
<tr>
<th class="sort-desc"><a href="/">Title</a></th>
<th class="active sort-asc"><a href="/">Created</a></th>
</tr>
</thead>
<tbody>
<tr class="no-data">
<td colspan="100" class="nolink">
<p class="no-data">
There are no records in this view.
</p>
</td>
</tr>
</tbody>
</table>
</div>
### Row classes
The following colored classes are available to use on the table row elements.
<div class="control-list">
<table class="table data">
<thead>
<tr>
<th class="sort-desc"><a href="/">Class</a></th>
</tr>
</thead>
<tbody>
<tr><td>Normal text</td></tr>
<tr class="hidden"><td>.hidden</td></tr>
<tr class="strike"><td>.strike</td></tr>
<tr class="frozen"><td>.frozen</td></tr>
<tr class="processing"><td>.processing</td></tr>
<tr class="negative"><td>.negative</td></tr>
<tr class="positive"><td>.positive</td></tr>
<tr class="disabled"><td>.disabled / .deleted</td></tr>
<tr class="new"><td>.new / .important</td></tr>
<tr class="safe"><td>.safe / .special</td></tr>
</tbody>
</table>
</div>
### Status column
It might be fun to include a status column!
<div class="control-list">
<table class="table data">
<thead>
<tr>
<th style="width: 150px"><span>Status</span></th>
<th class="active sort-asc"><a href="/">Title</a></th>
</tr>
</thead>
<tbody>
<tr>
<td>
<span class="wn-icon-circle text-muted">
Draft
</span>
</td>
<td>Welcome to Winter</td>
</tr>
<tr>
<td>
<span class="wn-icon-circle text-info">
Pending
</span>
</td>
<td>What a wonderful day</td>
</tr>
<tr>
<td>
<span class="wn-icon-circle text-success">
Approved
</span>
</td>
<td>The sun is shining</td>
</tr>
<tr>
<td>
<span class="wn-icon-circle text-danger">
Cancelled
</span>
</td>
<td>The weather is sweet here</td>
</tr>
</tbody>
</table>
</div>
### Badge column
You can also include an icon badge inside a column.
<div class="control-list">
<table class="table data">
<thead>
<tr>
<th style="width: 150px"><span>Status</span></th>
<th class="active sort-asc"><a href="/">Title</a></th>
</tr>
</thead>
<tbody>
<tr>
<td>
<span class="list-badge badge-info">
<i class="icon-info"></i>
</span>
Draft
</td>
<td>Welcome to Winter</td>
</tr>
<tr>
<td>
<span class="list-badge badge-warning">
<i class="icon-exclamation"></i>
</span>
Pending
</td>
<td>What a wonderful day</td>
</tr>
<tr>
<td>
<span class="list-badge badge-success">
<i class="icon-check"></i>
</span>
Approved
</td>
<td>The sun is shining</td>
</tr>
<tr>
<td>
<span class="list-badge badge-danger">
<i class="icon-times"></i>
</span>
Cancelled
</td>
<td>The weather is sweet here</td>
</tr>
</tbody>
</table>
</div>
### Linking rows
You may link an entire row by adding the `data-control="rowlink"` attribute to the table element. The first table data (TD) column with an anchor will be used to link the entire row. To bypass this behavior, simply add the `nolink` class to the column.
<div class="control-list">
<table class="table data" data-control="rowlink">
<tbody>
<tr>
<td>
<a href="https://wintercms.com">Link to this</a>
</td>
<td>Row will be linked</td>
<td>This will also be linked</td>
<td class="nolink">No link applied here</td>
</tr>
</tbody>
</table>
</div>
### Button column
You may add a small button to a list column by adding the `column-button` class to the table data (TD) element.
<div class="control-list">
<table class="table data" data-control="rowlink">
<thead>
<tr>
<th style="width: 150px"><span>Action</span></th>
<th><a href="javascript:;">Name</a></th>
</tr>
</thead>
<tbody>
<tr>
<td class="column-button nolink">
<a
href="http://google.com"
target="_blank"
class="btn btn-secondary btn-sm">
Open Google
</a>
</td>
<td>
<a href="javascript:;">
Petoria
</a>
</td>
</tr>
</tbody>
</table>
</div>

View File

@@ -0,0 +1,91 @@
# Loading indicators
## Container Loading Indicator
#### Loading Indicator
A loading indicator used in a container.
<div class="loading-indicator-container">
<div class="loading-indicator">
<span></span>
</div>
<p>This is some content inside the container</p>
<p>The loading indicator must be prepended to it</p>
</div>
#### Text Loading Indicator
A loading indicator can have text by adding a `<div>` element inside.
<div class="loading-indicator-container">
<div class="loading-indicator">
<span></span>
<div>Loading...</div>
</div>
</div>
#### Loading Indicator Sizes
A loading indicator can have a size by adding `size-X` to the container. These sizes are available: **size-small**.
<div class="loading-indicator-container">
<div class="loading-indicator size-small">
<span></span>
<div>Loading (size-small)</div>
</div>
</div>
#### Loading Indicator Alignment
A loading indicator can be aligned to the center by adding `indicator-center` to the container and/or indicator.
<div class="loading-indicator-container">
<div class="loading-indicator indicator-center">
<span></span>
</div>
</div>
You may add some optional text:
<div class="loading-indicator-container">
<div class="loading-indicator indicator-center">
<span></span>
<div>Loading...</div>
</div>
</div>
# Example
<div class="loading-indicator-container">
<div class="loading-indicator">
<span></span>
</div>
<p>This is some content inside the container</p>
<p>The loading indicator must be prepended to it</p>
</div>
<div class="loading-indicator-container">
<div class="loading-indicator">
<span></span>
<div>Loading...</div>
</div>
</div>
<div class="loading-indicator-container">
<div class="loading-indicator indicator-inset">
<span></span>
<div>Loading (inset)</div>
</div>
</div>
<div class="loading-indicator-container">
<div class="loading-indicator size-small">
<span></span>
<div>Loading (size-small)</div>
</div>
</div>
<div class="loading-indicator-container">
<div class="loading-indicator indicator-center">
<span></span>
</div>
</div>

View File

@@ -0,0 +1,23 @@
### Basic example
<div class="control-pagination">
<span class="page-iteration">Displayed records: 1-5 of 20</span>
<a href="#" class="page-back" title="Previous page"></a><a href="#" class="page-next" title="Next page"></a>
</div>
### Complete example
<div class="control-pagination">
<span class="page-iteration">Displayed records: 1-5 of 20</span>
<span class="page-first" title="First page"></span>
<span class="page-back" title="Previous page"></span>
<select
name="page"
class="form-control custom-select select-no-search">
<option value="1" selected>1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<a href="#" class="page-next" title="Next page"></a>
<a href="#" class="page-last" title="Last page"></a>
</div>

View File

@@ -0,0 +1,131 @@
# Popover
Renders a richer version of a tooltip, called a popover.
## Examples
### Basic usage
You may add `data-control="popover"` to an anchor or button to activate a popover. Use the `data-content` attribute to specify the contents.
<a
href="javascript:;"
class="btn btn-primary"
data-control="popover"
data-content="I am a standard popover">
Basic popover
</a>
### Template content
Define the popover content as a template and reference it with `data-content-from="#myPopoverContent"`.
```html
<script type="text/template" id="myPopoverContent">
<div class="popover-head">
<h3>Popover</h3>
<button type="button" class="close" data-dismiss="popover">&times;</button>
</div>
<div class="popover-body">
I am a popover
</div>
</script>
```
<div style="display:none" id="myPopoverContent">
<div class="popover-head">
<h3>Popover</h3>
<button type="button" class="close" data-dismiss="popover">&times;</button>
</div>
<div class="popover-body">
I am a popover
</div>
</div>
<a
href="javascript:;"
class="btn btn-primary"
data-control="popover"
data-width="200"
data-content-from="#myPopoverContent">
Template popover
</a>
### Event specified content
```js
$('#btn1').on('showing.oc.popover', function(e, popover) {
popover.options.content = '<div class="popover-body">Some other content</div>'
})
```
<a
href="javascript:;"
class="btn btn-primary"
data-control="popover"
data-placement="right"
id="btn1">
Event content popover
</a>
<script>
$(document).ready(function() {
$('#btn1').on('showing.oc.popover', function(e, popover) {
popover.options.content = '<div class="popover-body">Some other content</div>'
})
})
</script>
## JavaScript API
```js
$('#element').ocPopover({
content: '<p>This is a popover</p>'
placement: 'top'
})
```
### Supported methods
`.ocPopover('hide')`
Closes the popover. There are 3 ways to close the popover: call it's `hide()` method, trigger the `close.oc.popover` on any element inside the popover or click an element with attribute `data-dismiss="popover"` inside the popover.
### Supported options
- `placement`: top | bottom | left | right | center. The placement could automatically be changed if the popover doesn't fit into the desired position.
- `fallbackPlacement`: top | bottom | left | right. The placement to use if the default placement and all other possible placements do not work. The default value is "bottom".
- `content`: content HTML string or callback
- `contentFrom`: selector to source the content HTML
- `width`: content width, optional. If not specified, the content width will be used.
- `modal`: make the popover modal
- `highlightModalTarget`: "pop" the popover target above the overlay, making it highlighted. The feature assigns the target position relative.
- `closeOnPageClick`: close the popover if the page was clicked outside the popover area.
- `container`: the popover container selector or element. The default container is the document body. The container must be relative positioned.
- `containerClass` - a CSS class to apply to the popover container element
- `offset` - offset in pixels to add to the calculated position, to make the position more "random"
- `offsetX` - X offset in pixels to add to the calculated position, to make the position more "random". If specified, overrides the offset property for the bottom and top popover placement.
- `offsetY` - Y offset in pixels to add to the calculated position, to make the position more "random". If specified, overrides the offset property for the left and right popover placement.
- `useAnimation`: adds animation to the open and close sequence, the equivalent of adding the CSS class 'fade' to the containerClass.
### Supported events
- `showing.oc.popover` - triggered before the popover is displayed. Allows to override the popover options (for example the content) or cancel the action with e.preventDefault()
- `show.oc.popover` - triggered after the popover is displayed.
- `hiding.oc.popover` - triggered before the popover is closed. Allows to cancel the action with e.preventDefault()
- `hide.oc.popover` - triggered after the popover is hidden.

View File

@@ -0,0 +1,152 @@
# Popups
Displays a modal popup, based on the Bootstrap modal implementation.
- [Examples](#examples)
- [Inline popups](#inline-popups)
- [Remote popups](#remote-popups)
- [API documentation](#api-docs)
<a name="examples"></a>
## Examples
<a data-toggle="modal" href="#contentBasic" class="btn btn-primary btn-lg">Launch basic content</a>
<div class="control-popup modal fade" id="contentBasic" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<p>This is a very basic example of a popup...</p>
</div>
</div>
</div>
</div>
<a data-toggle="modal" href="#content-confirmation" class="btn btn-primary btn-lg">Launch Confirmation dialog</a>
<div class="control-popup modal fade" id="content-confirmation" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">Are you sure you wanna do that?</h4>
</div>
<div class="modal-body">
<p>This is your last chance. After this, there is no turning back.</p>
<p>You take the blue pill - the story ends, you wake up in your bed and believe whatever you want to believe. You take the red pill - you stay in Wonderland, and I show you how deep the rabbit hole goes.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Blue Pill</button>
<button type="button" class="btn btn-primary" data-dismiss="modal">Red Pill</button>
</div>
</div>
</div>
</div>
<a name="inline-popups"></a>
## Inline popups
An inline popup places the popup content inside the current page, hidden from the view. For example, this container will not be visible on the page.
```html
<div class="control-popup modal fade" id="contentBasic">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<p>This is a very basic example of a popup...</p>
</div>
</div>
</div>
</div>
```
Use the `data-toggle="modal"` HTML attribute to launch this container as a popup.
```html
<a data-toggle="modal" href="#contentBasic" class="btn btn-primary btn-lg">
Launch basic content
</a>
```
<a name="remote-popups"></a>
## Remote popups
Content for the popup can be loaded remotely using an AJAX request. Use the `data-handler` attribute to populate a popup with the contents of an AJAX handler.
```html
<a
data-control="popup"
data-handler="onLoadContent"
href="javascript:;"
class="btn btn-primary btn-lg">
Launch Ajax Form
</a>
```
Using the `data-ajax` attribute you can refer to an external file or URL directly.
```html
<a
data-control="popup"
data-ajax="popup-content.htm"
href="javascript:;"
class="btn btn-primary btn-lg">
Launch Ajax Form
</a>
```
The partial for your rendered popup should follow this structure:
```html
<div class="modal-header">
<button type="button" class="close" data-dismiss="popup">&times;</button>
<h4 class="modal-title">
<!-- Modal header title goes here -->
Send email
</h4>
</div>
<div class="modal-body">
<!-- Any popup content goes here -->
<?= $this->customFormWidget->render() ?>
</div>
<div class="modal-footer">
<!-- Popup action buttons go here -->
<button
type="submit"
class="btn btn-primary wn-icon-send"
data-load-indicator="Sending">
Send
</button>
<button
type="button"
class="btn btn-default"
data-dismiss="popup">
<?= e(trans('backend::lang.relation.close')) ?>
</button>
</div>
```
<a name="api-docs"></a>
## API documentation
### Options:
- `content` - content HTML string or callback
### Data attributes
- `data-control="popup"` - enables the ajax popup plugin
- `data-ajax="popup-content.htm"` - ajax content to load
- `data-handler="onLoadContent"` - Winter ajax request name
- `data-keyboard="false"` - Allow popup to be closed with the keyboard
- `data-extra-data="file_id: 1"` - Winter ajax request data
- `data-size="large"` - Popup size, available sizes: `giant`, `huge`, `large`, `small`, `tiny`, `adaptive` (will scale to fit the window)
- `data-adaptive-height="false"` - Allow the popup to fill the height of the screen
### JavaScript API
```js
$('a#someLink').popup({ ajax: 'popup-content.htm' })
$('a#someLink').popup({ handler: 'onLoadSomePopup' })
$('a#someLink').popup({ handler: 'onLoadSomePopup', extraData: { id: 3 } })
```

View File

@@ -0,0 +1,9 @@
Progress bar
# Example
<div class="progress">
<div class="progress-bar" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" style="width: 60%;">
<span class="sr-only">60% Complete</span>
</div>
</div>

View File

@@ -0,0 +1,84 @@
# Scoreboard
### Scoreboard
<div class="scoreboard">
<div data-control="toolbar">
<div class="scoreboard-item title-value">
<h4>Weight</h4>
<p>100</p>
<p class="description">unit: kg</p>
</div>
<div class="scoreboard-item title-value">
<h4>Comments</h4>
<p class="positive">44</p>
<p class="description">previous month: 32</p>
</div>
<div class="scoreboard-item title-value">
<h4>Latest commenter</h4>
<p class="wn-icon-star">John Smith</p>
<p class="description">registered: yes</p>
</div>
</div>
</div>
### Complete example
<div class="scoreboard">
<div data-control="toolbar">
<div class="scoreboard-item control-chart" data-control="chart-pie">
<ul>
<li data-color="#95b753">Published <span>84</span></li>
<li data-color="#e5a91a">Drafts <span>12</span></li>
<li data-color="#cc3300">Deleted <span>18</span></li>
</ul>
</div>
<div class="scoreboard-item control-chart" data-control="chart-bar">
<ul>
<li data-color="#95b753">Published <span>84</span></li>
<li data-color="#e5a91a">Drafts <span>12</span></li>
<li data-color="#cc3300">Deleted <span>18</span></li>
</ul>
</div>
<div class="scoreboard-item title-value">
<h4>Weight</h4>
<p>100</p>
<p class="description">unit: kg</p>
</div>
<div class="scoreboard-item title-value">
<h4>Comments</h4>
<p class="positive">44</p>
<p class="description">previous month: 32</p>
</div>
<div class="scoreboard-item title-value">
<h4>Length</h4>
<p class="negative">31</p>
<p class="description">previous: 42</p>
</div>
<div class="scoreboard-item title-value">
<h4>Latest commenter</h4>
<p class="wn-icon-star">John Smith</p>
<p class="description">registered: yes</p>
</div>
<div class="scoreboard-item title-value" data-control="goal-meter" data-value="88">
<h4>goal meter</h4>
<p>88%</p>
<p class="description">37 posts remain</p>
</div>
<div class="scoreboard-item title-value goal-meter-inverse" data-control="goal-meter" data-value="88">
<h4>goal meter</h4>
<p>88%</p>
<p class="description">37 posts remain</p>
</div>
</div>
</div>

View File

@@ -0,0 +1,156 @@
# Select
### Select
Custom select control.
<select class="form-control custom-select">
<option selected="selected" value="2">Approved</option>
<option value="3">Deleted</option>
<option value="1">New</option>
</select>
## Sizes
### Small size
<div class="form-group form-group-sm">
<select class="form-control custom-select">
<option value="1" selected="selected">One</option>
<option value="2">Two</option>
</select>
</div>
### Large size
<div class="form-group form-group-lg">
<select class="form-control custom-select">
<option value="1" selected="selected">One</option>
<option value="2">Two</option>
</select>
</div>
## Options
### Disable search
Add the `select-no-search` CSS class to disable searching.
<div class="form-group">
<select class="form-control custom-select select-no-search">
<option value="1" selected="selected">One</option>
<option value="2" selected="selected">Two</option>
</select>
</div>
### Dynamic option creation
In addition to a pre-populated menu of options, Select widgets may dynamically create new options from textual input by the user in the search box. This feature is called "tagging". To enable tagging, set the `tags` option to `true`:
<select
class="form-control custom-select"
data-tags="true"
></select>
## Option groups
Use the `optgroup` element to create option groups.
<select class="form-control custom-select">
<option value="1">Please select an option</option>
<option value="2">Ungrouped option</option>
<optgroup label="Option Group">
<option value="3">Grouped option</option>
<option value="4">Another option</option>
<option value="4">Third option</option>
</optgroup>
</select>
## AJAX search
Use the `data-handler` attribute to source the select options from an AJAX handler.
```html
<select
class="form-control custom-select"
data-handler="onGetOptions"
data-minimum-input-length="2"
data-ajax-delay="300"
data-request-data="foo: 'bar'"
></select>
```
The AJAX handler should return results in the [Select2 data format](https://select2.org/data-sources/formats).
```php
public function onGetOptions()
{
return [
'results' => [
[
'id' => 1,
'text' => 'Foo'
],
[
'id' => 2,
'text' => 'Bar'
]
...
]
];
}
```
Or a more full-featured example:
```php
public function onGetOptions()
{
return [
'results' => [
[
'id' => 1,
'text' => 'Foo',
'disabled' => true
],
[
'id' => 2,
'text' => 'Bar',
'selected' => true
],
[
'text' => 'Group',
'children' => [
[
'id' => 3,
'text' => 'Child 1'
],
[
'id' => 4,
'text' => 'Child 2'
]
...
]
]
...
],
'pagination' => [
'more' => true
]
];
}
```
The results array can be assigned to either the `result` or `results` key. As an alternative to the Select2 format, results can also be provided as an associative array (also assigned to either key). Due to the fact that JavaScript does not guarantee the order of object properties, we suggest the method above for defining results.
```php
public function onGetOptions()
{
$results = [
'key' => 'value',
...
];
return ['result' => $results];
}
```

View File

@@ -0,0 +1,7 @@
Includes scaffold for a basic site.
Reset
Normalize
Grid system
Print
Typography

View File

@@ -0,0 +1,155 @@
# Tab control
This plugin is a wrapper for the Twitter Bootstrap Tab component. It provides the following features:
- Adding tabs
- Optional close icons with 2 states (modified / unmodified). The icon state can be changed by triggering the modified.oc.tab/unmodified.oc.tab events on any element within tab, or on the tab itself.
- Removing tabs with the Close icon, or with triggering an event from inside a tab pane or tab. The removing can be canceled if the `confirm.oc.tab` event handler returns `false`.
- Scrolling tabs if they do not fit the screen
- Collapsible tabs
### Supported CSS modifiers
These modifiers can be added in addition to the `control-tabs` class:
- `tabs-inset` - Applies a negative margin to the tabs allowing them to sit well inside a padded container.
- `tabs-offset` - Applies a positive padding to tabs so they sit well inside a flush (non padded) container.
- `tabs-flush` - Tabs to sit flush to the element above it.
### Master tabs
```html
<div class="control-tabs master-tabs" data-control="tab">
<ul class="nav nav-tabs">
<li class="active"><a href="#primaryTabOne">One</a></li>
<li><a href="#primaryTabTwo">Two</a></li>
<li><a href="#primaryTabThree">Three</a></li>
</ul>
<div class="tab-content">
<div class="tab-pane active">
Tab one content
</div>
<div class="tab-pane">
Tab two content
</div>
<div class="tab-pane">
Tab three content
</div>
</div>
</div>
```
### Primary tabs
```html
<div class="control-tabs primary-tabs" data-control="tab">
<ul class="nav nav-tabs">
<li class="active"><a href="#primaryTabOne">One</a></li>
<li><a href="#primaryTabTwo">Two</a></li>
<li><a href="#primaryTabThree">Three</a></li>
</ul>
<div class="tab-content">
<div class="tab-pane active">
Tab one content
</div>
<div class="tab-pane">
Tab two content
</div>
<div class="tab-pane">
Tab three content
</div>
</div>
</div>
```
> **Note**: Primary tabs in the Winter back-end are inset by default and you should use `.tabs-no-inset` to disable this.
### Secondary tabs
```html
<div class="control-tabs secondary-tabs" data-control="tab">
<ul class="nav nav-tabs">
<li class="active"><a href="#secondaryTabOne">One</a></li>
<li><a href="#secondaryTabTwo">Two</a></li>
<li><a href="#secondaryTabThree">Three</a></li>
</ul>
<div class="tab-content">
<div class="tab-pane active">
Tab one content
</div>
<div class="tab-pane">
Tab two content
</div>
<div class="tab-pane">
Tab three content
</div>
</div>
</div>
```
### Content tabs
```html
<div class="control-tabs content-tabs" data-control="tab">
<ul class="nav nav-tabs">
<li class="active"><a href="#contentTabOne">One</a></li>
<li><a href="#contentTabTwo">Two</a></li>
<li><a href="#contentTabThree">Three</a></li>
</ul>
<div class="tab-content">
<div class="tab-pane active">
Tab one content
</div>
<div class="tab-pane">
Tab two content
</div>
<div class="tab-pane">
Tab three content
</div>
</div>
</div>
```
### Supported data attributes:
- `data-control="tab"` - creates the tab control from an element
- `data-closable` - enables the Close Tab feature
- `data-pane-classes` - a list of CSS classes to apply new pane elements
Example with data attributes:
```html
<div class="control-tabs master" data-control="tab" data-closable>
<ul class="nav nav-tabs">
<li class="active"><a href="#home">Home</a></li>
</ul>
<div class="tab-content">
<div class="tab-pane active">Home</div>
</div>
</div>
```
### JavaScript API
- `$('#mytabs').ocTab({closable: true, closeConfirmation: 'Close this tab? Unsaved data will be lost.'})`
- `$('#mytabs').ocTab('addTab', 'Tab title', 'Tab content', identifier)` - adds tab. The optional identifier parameter allows to associate a identifier with a tab. The identifier can be used with the `goTo()` method to find and open a tab by it's identifier.
- `$('#mytabs').ocTab('closeTab', '.nav-tabs > li.active', true)` - closes a tab. The second argument can point to a tab or tab pane. The thrid argument determines whether the tab should be closed without the user confirmation. The default value is `false`.
- `$('.nav-tabs > li.active').trigger('close.oc.tab')` - another way to close a tab. The event can be triggered on a tab, tab pane or any element inside a tab or tab pane.
- `$('#mytabs').ocTab('modifyTab', '.nav-tabs > li.active')` - marks a tab as modified. Use the `unmodifyTab` to mark a tab as unmodified.
- `$('.nav-tabs > li.active').trigger('modified.oc.tab')` - another way to mark a tab as modified. The event can be triggered on a tab, tab pane or any element inside a tab or tab pane. Use the `unmodified.oc.tab` to mark a tab as unmodified.
- `$('#mytabs').ocTab('goTo', 'someidentifier')` - Finds a tab by it's identifier and opens it.
- `$('#mytabs').ocTab('goToPane', '.tab-content .tab-pane:first')` - Opens a tab in context of it's content (pane element)
### Supported options:
- `closable` - adds the "close" icon to the tab and lets users to close tabs. Corresponds the `data-closable` attribute.
- `closeConfirmation` - a confirmation to show when a user tries to close a modified tab. Corresponds the `data-close-confirmation` attribute. The confirmation is displayed only if the tab was modified.
- `slidable` - allows the tabs to be switched with the swipe gesture on touch devices. Corresponds the `data-slidable` attribute.
- `paneClasses` - a list of CSS classes to apply new pane elements. Corresponds to the `data-pane-classes` attribute.
- `maxTitleSymbols` - the maximum number of characters in tab titles.
- `titleAsFileNames` - treat tab titles as file names. In this mode only the file name part is displayed in the tab, and the directory part is hidden.
### Supported events:
- `beforeClose.oc.tab` - triggered on a tab pane element before tab is closed by the user. Call the event's `preventDefault()` method to cancel the action.
- `afterAllClosed.oc.tab` - triggered after all tabs have been closed

View File

@@ -0,0 +1,162 @@
# Toolbar
A scrollable set of buttons aligned to the left with a fixed right section.
All toolbar items (`toolbar-item`) should have a fixed width, except for the primary item (`toolbar-primary`) which will stretch. In the Winter backend you can use the `data-calculate-width` attribute to have these widths calculated dynamically for you.
## Basic toolbar
<div class="control-toolbar">
<div class="toolbar-item toolbar-primary">
<div data-control="toolbar">
<button type="button" class="btn btn-primary wn-icon-plus">Create post</button>
<button type="button" class="btn btn-default wn-icon-copy">Copy</button>
<button type="button" class="btn btn-default wn-icon-trash">Delete</button>
<button type="button" class="btn btn-default wn-icon-magic">Publish</button>
<button type="button" class="btn btn-default wn-icon-power-off">Unpublish</button>
<button type="button" class="btn btn-default wn-icon-clock-o">Timer</button>
<button type="button" class="btn btn-default wn-icon-mail-reply-all">Send by email</button>
<button type="button" class="btn btn-default wn-icon-hdd-o">Archive</button>
</div>
</div>
<div class="toolbar-item" style="width: 110px">
<input placeholder="search..." type="text" name="" value="" class="form-control icon search" />
</div>
</div>
### Button groups
<div class="control-toolbar">
<div class="toolbar-item toolbar-primary">
<div data-control="toolbar">
<div class="btn-group">
<button type="button" class="btn btn-default wn-icon-mail-reply-all">Send by email</button>
<button type="button" class="btn btn-default wn-icon-hdd-o">Archive</button>
</div>
</div>
</div>
<div class="toolbar-item" style="width: 110px">
<input placeholder="search..." type="text" name="" value="" class="form-control icon search" />
</div>
</div>
### Button with Tooltips
<div class="control-toolbar">
<div class="toolbar-item toolbar-primary">
<div data-control="toolbar">
<button
type="button"
class="btn btn-default wn-icon-download"
title="Hold down shift for more options"
data-control="tooltip"
data-placement="bottom"
data-container="body">
Export
</button>
</div>
</div>
<div class="toolbar-item" style="width: 110px">
<input placeholder="search..." type="text" name="" value="" class="form-control icon search" />
</div>
</div>
### Dropdown buttons
<div class="control-toolbar">
<div class="toolbar-item toolbar-primary">
<div data-control="toolbar">
<div class="dropdown dropdown-fixed">
<button
type="button"
class="btn btn-default wn-icon-users"
data-toggle="dropdown">
Assign selected to...
</button>
<ul class="dropdown-menu" data-dropdown-title="Assign selected to...">
<li><a href="#" tabindex="-1" class="wn-icon-user">Sally</a></li>
<li><a href="#" tabindex="-1" class="wn-icon-user">Steve</a></li>
<li><a href="#" tabindex="-1" class="wn-icon-user">Justin</a></li>
</ul>
</div>
</div>
</div>
<div class="toolbar-item" style="width: 110px">
<input placeholder="search..." type="text" name="" value="" class="form-control icon search" />
</div>
</div>
## Editor toolbar
<div class="layout control-toolbar editor-toolbar">
<div class="layout-cell toolbar-item">
<div data-control="toolbar">
<!-- Dropdown item -->
<div class="dropdown dropdown-fixed">
<button
type="button"
class="btn"
title="Formatting"
data-toggle="dropdown"
data-control="tooltip"
data-placement="bottom"
data-container="body">
<i class="icon-paragraph"></i>
</button>
<ul class="dropdown-menu" data-dropdown-title="Formatting">
<li><a href="#" tabindex="-1" class="wn-icon-quote-right">Quote</a></li>
<li><a href="#" tabindex="-1" class="wn-icon-code">Code</a></li>
<li><a href="#" tabindex="-1" class="wn-icon-header">Header 1</a></li>
<li><a href="#" tabindex="-1" class="wn-icon-header">Header 2</a></li>
<li><a href="#" tabindex="-1" class="wn-icon-header">Header 3</a></li>
<li><a href="#" tabindex="-1" class="wn-icon-header">Header 4</a></li>
<li><a href="#" tabindex="-1" class="wn-icon-header">Header 5</a></li>
<li><a href="#" tabindex="-1" class="wn-icon-header">Header 6</a></li>
</ul>
</div>
<!-- Item with tooltip -->
<button
type="button"
class="btn"
title="Bold"
data-control="tooltip"
data-placement="bottom"
data-container="body">
<i class="icon-bold"></i>
</button>
<!-- Disabled item -->
<button type="button" disabled class="btn">
<i class="icon-italic"></i>
</button>
<button type="button" class="btn">
<i class="icon-list-ul"></i>
</button>
<button type="button" class="btn">
<i class="icon-list-ol"></i>
</button>
<button type="button" class="btn">
<i class="icon-link"></i>
</button>
<button type="button" class="btn">
<i class="icon-minus"></i>
</button>
</div>
</div>
<div class="toolbar-item" style="width: 80px">
<button type="button" class="btn wn-icon-eye"></button>
<button type="button" class="btn wn-icon-expand"></button>
</div>
</div>

View File

@@ -0,0 +1,30 @@
# Tooltips
Tooltips are an alternative to the standard browser title tooltip.
## Tooltip markup
A standard tooltip
<div class="tooltip fade top in">
<div class="tooltip-arrow"></div>
<div class="tooltip-inner">Create a new blog post based on this</div>
</div>
## Spawning tooltips
Tooltips can be automatically created when the mouse enters an element using the `data-toggle="tooltip"` tag.
<a
href="javascript:;"
data-toggle="tooltip"
data-placement="left"
data-delay="500"
title="Tooltip content">
Some link
</a>
# Example
<div class="tooltip fade top in">
<div class="tooltip-arrow"></div>
<div class="tooltip-inner">Create a new blog post based on this</div>
</div>

View File

@@ -0,0 +1,129 @@
Utility styles are a collection of useful classes designed to reduce the need to create a stylesheet for basic styling needs, such as spacing and positioning.
### Branding
```css
.br-p { color: @brand-primary; }
.br-s { color: @brand-secondary; }
.br-a { color: @brand-accent; }
.br-p-s10 { color: saturate(@brand-primary, 10%); }
.br-s-s10 { color: saturate(@brand-secondary, 10%); }
.br-a-s10 { color: saturate(@brand-accent, 10%); }
.br-p-s20 { color: saturate(@brand-primary, 20%); }
.br-s-s20 { color: saturate(@brand-secondary, 20%); }
.br-a-s20 { color: saturate(@brand-accent, 20%); }
.bg-p { background-color: @brand-primary; }
.bg-s { background-color: @brand-secondary; }
.bg-a { background-color: @brand-accent; }
.bg-p-s10 { background-color: saturate(@brand-primary, 10%); }
.bg-s-s10 { background-color: saturate(@brand-secondary, 10%); }
.bg-a-s10 { background-color: saturate(@brand-accent, 10%); }
.bg-p-s20 { background-color: saturate(@brand-primary, 20%); }
.bg-s-s20 { background-color: saturate(@brand-secondary, 20%); }
.bg-a-s20 { background-color: saturate(@brand-accent, 20%); }
```
### Typography
```css
.t-ww { word-wrap: break-word; }
.t-nw { white-space: nowrap; }
```
### Positioning
```css
.pos-r { position: relative !important; }
.pos-a { position: absolute !important; }
.pos-f { position: fixed !important; }
```
### Width
```css
.w-sm { width: 25% !important; }
.w-md { width: 50% !important; }
.w-lg { width: 75% !important; }
.w-full { width: 100% !important; }
.w-100 { width: 100px !important; }
.w-120 { width: 120px !important; }
.w-130 { width: 130px !important; }
.w-140 { width: 140px !important; }
.w-200 { width: 200px !important; }
.w-300 { width: 300px !important; }
.w-350 { width: 350px !important; }
```
### Margin
Assign `margin` to an element with these shorthand classes. The `@spacer` value is set to 20px by default.
```css
.m-a-0 { margin: 0 !important; }
.m-t-0 { margin-top: 0 !important; }
.m-r-0 { margin-right: 0 !important; }
.m-b-0 { margin-bottom: 0 !important; }
.m-l-0 { margin-left: 0 !important; }
.m-a { margin: @spacer !important; }
.m-t { margin-top: @spacer-y !important; }
.m-r { margin-right: @spacer-x !important; }
.m-b { margin-bottom: @spacer-y !important; }
.m-l { margin-left: @spacer-x !important; }
.m-x { margin-right: @spacer-x !important; margin-left: @spacer-x !important; }
.m-y { margin-top: @spacer-y !important; margin-bottom: @spacer-y !important; }
.m-x-auto { margin-right: auto !important; margin-left: auto !important; }
.m-a-md { margin: (@spacer-y * 1.5) !important; }
.m-t-md { margin-top: (@spacer-y * 1.5) !important; }
.m-r-md { margin-right: (@spacer-y * 1.5) !important; }
.m-b-md { margin-bottom: (@spacer-y * 1.5) !important; }
.m-l-md { margin-left: (@spacer-y * 1.5) !important; }
.m-x-md { margin-right: (@spacer-x * 1.5) !important; margin-left: (@spacer-x * 1.5) !important; }
.m-y-md { margin-top: (@spacer-y * 1.5) !important; margin-bottom: (@spacer-y * 1.5) !important; }
.m-a-lg { margin: (@spacer-y * 3) !important; }
.m-t-lg { margin-top: (@spacer-y * 3) !important; }
.m-r-lg { margin-right: (@spacer-y * 3) !important; }
.m-b-lg { margin-bottom: (@spacer-y * 3) !important; }
.m-l-lg { margin-left: (@spacer-y * 3) !important; }
.m-x-lg { margin-right: (@spacer-x * 3) !important; margin-left: (@spacer-x * 3) !important; }
.m-y-lg { margin-top: (@spacer-y * 3) !important; margin-bottom: (@spacer-y * 3) !important; }
```
### Padding
Assign `padding` to an element with these shorthand classes. The `@spacer` value is set to 20px by default.
```css
.p-a-0 { padding: 0 !important; }
.p-t-0 { padding-top: 0 !important; }
.p-r-0 { padding-right: 0 !important; }
.p-b-0 { padding-bottom: 0 !important; }
.p-l-0 { padding-left: 0 !important; }
.p-a { padding: @spacer !important; }
.p-t { padding-top: @spacer-y !important; }
.p-r { padding-right: @spacer-x !important; }
.p-b { padding-bottom: @spacer-y !important; }
.p-l { padding-left: @spacer-x !important; }
.p-x { padding-right: @spacer-x !important; padding-left: @spacer-x !important; }
.p-y { padding-top: @spacer-y !important; padding-bottom: @spacer-y !important; }
.p-a-md { padding: (@spacer-y * 1.5) !important; }
.p-t-md { padding-top: (@spacer-y * 1.5) !important; }
.p-r-md { padding-right: (@spacer-y * 1.5) !important; }
.p-b-md { padding-bottom: (@spacer-y * 1.5) !important; }
.p-l-md { padding-left: (@spacer-y * 1.5) !important; }
.p-x-md { padding-right: (@spacer-x * 1.5) !important; padding-left: (@spacer-x * 1.5) !important; }
.p-y-md { padding-top: (@spacer-y * 1.5) !important; padding-bottom: (@spacer-y * 1.5) !important; }
.p-a-lg { padding: (@spacer-y * 3) !important; }
.p-t-lg { padding-top: (@spacer-y * 3) !important; }
.p-r-lg { padding-right: (@spacer-y * 3) !important; }
.p-b-lg { padding-bottom: (@spacer-y * 3) !important; }
.p-l-lg { padding-left: (@spacer-y * 3) !important; }
.p-x-lg { padding-right: (@spacer-x * 3) !important; padding-left: (@spacer-x * 3) !important; }
.p-y-lg { padding-top: (@spacer-y * 3) !important; padding-bottom: (@spacer-y * 3) !important; }
```