NOTE: See our Components documentation for an overview of Component Architecture if you want to build your own.

Stratus components are available on any page by adding the stratus component name. A few basic Stratus components are defined in the Stratus.js library. And Sitetheory has created custom Stratus Components which are specific to our platform. These are located in the most relevant related bundle’s Resources/public/js/stratus/ folder and defined in Sitetheory’s stratus config file (CoreBundle/Resources/public/js/boot/config.js, e.g. stratus-carousel.

Components For Functionality

Lazy Load Correct Sized Images

stratus-src

This stratus internal component allows you to load the best sized image based on the size of the container (XS, S, M, L, XL, HQ) so that it fills that area (which means it doesn’t load images larger than mobile devices need), and it doesn’t load elements that aren’t on the page yet.

Example

Load a default small image as a placeholder (useful for proportions and scaling), and then use the src path to find the best version of image.

1
    <img stratus-src src="foo-xs.jpg">

Do not load a default image, use stratus-src to find the best version of the the image.

1
    <img stratus-src="foo.jpg">

If you want a placeholder image to appear on the page, you can just enter that as the regular image src. It is usually recommended to specify the smallest version of the image, so that the image’s native ratio will be available to the CSS so that the height is correctly proportional to the width (which means when the real image loads the page isn’t going to shift as element heights change).

NOTE: If you use the lazy loading on images in your hard coded design template assets (not created by the CMS system so they don’t automatically have the different size options, e.g. XS, S, M, L, XL, HQ), you will need to create these versions of your images that the component can load. Your sizes should be the standard sizes, since we check the container and load the best size based on the expected size of the images.

XS: 200px S: 400px M: 600px L: 800px XL: 1000px HQ: 1200px

You can also use lazy loading on background images.

1
    <div stratus-src style="background-image:url(foo.jpg)">

You can also use lazy loading on background images.

1
        <div stratus-src style="background-image:url(foo.jpg)">

You can also use disable lazy-loading dynamically in Angular when only the data in the API will tell us if the image is eligible for lazy loading, by specify the value ‘false’. This is used in places like a IDX widget that displays images from third party servers that are not variable sizes.

1
            <div stratus-src="{{ model.images[0].lazy ? '' : 'false' }}" ng-style="{'background-image':'url({{ model.images[0].src }}'}"></div>

Classes

  • placeholder: When the image is first collected for lazy-loading a ‘placeholder’ class will be added to it, so that you can style default look of an image that isn’t loaded, e.g. gray background with a loading icon.
  • loading: when the image is on screen and is in the process of loading, a ‘loading’ class will be added.
  • loaded: when the image is loaded, the ‘loading’ class will be replaced by ‘loaded’. The loaded class should include a CSS animation that fades from opacity 0 to 1 to replace the current

Attribute Options:

  • stratus-src: (str|bool|null) If a string, stratus-src should point to the image path that you want to lazy-load. If you have specified a regular img src as a placeholder image (e.g. a small version), and you want to lazy load the best size of that image, than you can avoid typing out the path a second time and just specify the attribue stratus-src without a value and the system will load the best version of the current image src. If the value is false it should abort the lazy loading. This is necessary because when we load images dynamically in Angular (rather than Twig template) we can only manipulate the value not the attribute itself, so we will either pass in true or false.
  • data-hd: (bool, default: true) By default we will load hd images which are double the size of the parent container, so that they look good on retina devices. But you can disable this by passing in data-hd=”false”.
  • data-spy: (str) By default the image will load when it is “on screen”. But in some cases (like a Carousel) you need to specify a CSS selector for an alternative element on the screen that should trigger the loading, e.g. the container div.
  • data-ignore-visibility: (bool) normally it will look for the size of the container and load the correct image that will fill the container (assuming a 100% width is set on CSS). But if the container is invisible, it will try to go up the element tree to the first parent that is visible. This is often desirable because the parent is collapsed. However, in some cases, like a Carousel, if you have the parent width set explicitly on a containing element, you want to use that (not the outer carousel width). So you set data-ignoreVisibility=”true” and it will use the parent container width.
  • status-src-suffix: (json) (TODO: IMPLEMENT) specify alternative formatting for image sizes, e.g. by default we add -s, -m, -l, etc to the base image url, but for third party sources, that format may be different. e.g. here we would specify that small and medium use the -thumb and all others use the default image, e.g. no alternative size added
  • TODO: Determine if we still want this options, which seems to have been removed from the current stratus, but should be in the history if we want to reference what it used to do: data-disable-fadein: All images will fade in from opacity 0 to 1, when the placeholder class is replaced with the loaded class. If you have specified a src because you want a default placeholder image to show up, then obviously you don’t want the placeholder image to go invisible. So you should add a “disable-fadein” class to the image.

OnScreen

The OnScreen component will detect when an element is visible on the screen and add classes that can be styled in CSS.

Initiate the onScreen component by adding stratus-on-screen to any element.

1
2
3
        <div stratus-on-screen>Fancy Area</div>

This component will add classes to the element depending on the user's actions: 'on-screen' or 'off-screen' as well as 'scroll-up' or 'scroll-dDown'. You can then target any combination of these two options, to do some fancy things like make a secondary header appear when the main header is 'offscreen' but you are scrolling up. Or make CSS animations start only when you scroll them into view.
1
        <div stratus-on-screen class="on-screen scroll-down">Fancy Area</div>

Additional Options

  • data-target: the CSS selector of an alternative element that should have the classes added (instead of itself), e.g. a parent element. Defaults to the current element.
  • data-spy: the CSS selector of an an alternative element that should be watched to check if it’s on or off screen. Defaults to the current element.
  • data-offset: an integer (positive or negative) that determines where the spy element begins on the page. So if you set this to 200, the element onScreen class would be added to the target after the spy element was 200 pixels onto the screen.
  • data-event: one or more events names that can trigger actions. The only option at the moment is “reset” which allows the classes to be reset if the page is scrolled to the very top, or if the data-reset value is set when the page is scrolled to that position.
  • data-reset: an integer representing a vertical (y) pixel position on the page that should trigger a reset when the page is scrolled to that point (defaults to 0).

Embed

Because of the way Angular controls the DOM, it is not possible to just paste third party Javascript on the page (e.g. a Twitter widget), if it is inside any Angular controlled areas, e.g. any part of the page that is inside an ng-if, ng-repeat, ng-controller, etc, essentially almost anywhere. If you do, there will be timing issues because Angular removes elements from the DOM unpredictably and controls when they appear. So we have to use a component to load the third party code at the right time.

NOTE: this may not be implemented yet (10/14/2019)

1
2
3
    <stratus-embed scripts="['foo.js', 'bar.js']">
        <!-- code here -->
    </stratus-embed>

So looking at a third party embed code like Twitter (NOTE: we have a specific twitter component already):

1
<a href="https://twitter.com/intent/tweet?button_hashtag=gutensite&ref_src=twsrc%5Etfw" class="twitter-hashtag-button" data-show-count="false">Tweet #gutensite</a><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

Instead you would do this:

1
2
3
    <stratus-embed scripts="['https://platform.twitter.com/widgets.js']">
        <a href="https://twitter.com/intent/tweet?button_hashtag=gutensite&ref_src=twsrc%5Etfw" class="twitter-hashtag-button" data-show-count="false">Tweet #gutensite</a>
    </stratus-embed>

Twitter

Becuase of the way that Angular controls the DOM, it’s not possible to copy/paste third party embed code, so we have created a component that passes through the settings at the right time. It accepts the standard Twitter parameters for Twitter Component (https://developer.twitter.com/en/docs/twitter-for-websites/timelines/guides/parameter-reference).

1
<stratus-twitter-feed screen-name="gutensite"></stratus-twitter-feed>

HOW TO USE STANDARD ANGULAR TO DO COMMON COMPONENT-LIKE FEATURES

We do not need specific components to do common design template features anymore, instead we just use standard Angular. And we have a core components.css that applies basic styles to the examples below.

In 95% of cases we can use a simple CSS and Angular version of a carousel, instead of a third party library (e.g. stratus-carousel). This is easier to style, and doesn’t require loading any extra files. This requires a bit of HTML/Angular, so we have a Twig component that injects the necessary code onto a page which displays images or HTML slides.

Example See the Landing.html.twig Stream for an implementation of the ComponentsAdminList.html.twig carousel macro.

1
2
3
4
5
6
7
    {# Arguements:
        model - (default: 'model.data')
        ratio ('portrait', 'square', 'landscape', 'cinema')
        carouselType ('images', 'HTML')
        controlSize ('standard-controls', 'small-controls')
    #}
    {{ streamComponents.carousel('model.data', 'square', 'images') }}

ng-class

Use ng-class to add a class based on a conditions, e.g. ng-class=”{‘my-class’: myVariable}” will add “my-class” if “myVariable” is true.

ng-click or ng-hover

Use ng-click or ng-hover to modify variables that can be used on other elements that conditionally add a class with ng-class

Example

Add a “More Box”

We use a “More Box” for various popups on the site, e.g. immersive popups that dim the screen and show a popup in the middle of the site, or local popup that just covers a button locally.

Examples

For the Local Popup the button can contain the popup inside it.

Add a Drawer

It is often necessary to make a drawer slide in and out of the side of the website (e.g. a toolbar, or a responsive mobile menu drawer). This works basically exactly like a More Box, but with slightly different CSS. The core plugins.css has basic styling that makes the drawer and the app container slide in together, but you can customize specifics in your own CSS.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
        <!--Place button anywhere-->
        <a ng-click="myVariable=true">
            Toggle Drawer
        </a>

        <!--Place popup directly above closing body tag-->
        <div ng-class="{'show':myVariable}" class="drawer-position">
            <div class="drawer">
                <!--Optional close button-->
                <button type="button" class="btn-close" ng-click="myVariable=false">
                    <md-icon ng-class="{'show':myVariable}" md-svg-src="/Api/Resource?path=@SitetheoryCoreBundle:images/icons/actionButtons/close.svg" aria-hidden="true" role="img"></md-icon>
                <button>
                <!--Drawer content here-->
            </div>
        </div>

Components For Editing

TODO: this needs to be updated since it was written in 2017 because we moved to Angular and most editing is done with Angular Material widgets

Generally we use Angular Material components for enabling editing on a page. But Sitetheory has created custom Editing Components that are specifically intended to allow a designer to render controller elements on the page to give editing functionality. A component can be a simple display field to show the value of an entity, a text field that allows editing the value of an entity property, or it can be like a complex media selector that shows you all the elements you have selected and allows you to upload or select new media. Components render a template and add functionality to the page so the designer can control the user experience. Most components are set to auto-save changes, so the experience is much more responsive than traditional forms. Components are used extensively throughout the CMS admin and Live Edit mode.

See the Javascript documentation for detailed specs of each widget. TODO: update link to documentation once we move these to Sitetheory http://js.sitetheory.io/1/0/stratus.html

** TODO: update these to Stratus Components and document**

data-property (string): This is the model property that is being edited.

data-label (string): The label for the information being edited.

data-help (string): Additional information to help users, which will appear as a popover on a help icon.

data-template (string): This would be a full web path to a template file or a template key from config.js.

data-templates (JSON): This is a JSON object with names of the templates and a key or web path to the template that should be used for each part of the widget. Usually most components have only one template, but in cases like the Collection widget, there may be a list, container, and entity template, and this allows you to customize all of them, e.g. {“list”: “/path-to-list”, “container”: “/path-to-container”, “entity”: “/path-to-entity”

TODO: determine if this is used

TODO: determine if this is used

TODO: add documenation for our Editor

1
    <stratus-redactor></stratus-redactor>

Add pagination for a specific collection. TODO: Explain how stratus knows which Collection to paginate (does this need to be inside the parent element?) .. code-block:: html

linenos:<stratus-pagination></stratus-pagination>

TODO: is this still valid? data-meta: this allows you to pass in data to the collection widget so that it will be accessible in the template, e.g. when defining the widget on the DOM, add an attribute for data-meta=’{“foo”:”bar”}’ will pass in values to the template to be accessed as {{ globals.meta.foo }}

This adds a save button to the page to save current version. ** TODO: update these to Stratus Components and document**

This adds a publish button to the page to publish the current version. ** TODO: update these to Stratus Components and document**

This adds a delete button to the page to delete current record. ** TODO: update these to Stratus Components and document**

Add a “Help” icon that reveals more information on hover.

1
    <stratus-help flex="5">This field allows you to explain how awesome you are.</stratus-help>

Add different types of dynamic fields that allow you to enter a value and select a label to describe what kind of infromation this is, e.g. an email field, that lets you select “Main”, “Work”, “Personal” or enter your own custom label.

  • data-type (string): a string of one of the valid field types. A valid field type will add special styling, functionality, and validation relevant to that type of data. Valid options include: “phone”, “email”, “url”, “location”, “date”. If no valid type is specified it will just be a simple field.
  • data-options (array: required) an array of labels to choose from for this field e.g. [“Main”, “Mobile”, “Work”, “Personal”]
  • data-custom (boolean): specify true if you want users to be able to enter a custom value for the label. (default: true)
  • data-multiple (boolean): specify true if you want users to be able to add more than one version of this type of field, e.g. multiple phone numbers. (default: true)
  • location: when saved, a location will attempt to do a geolocation lookup and store the latitude/longitude of the address.
1
2
3
4
5
6
7
    <stratus-option-value flex="95" ng-show="model.completed"
        ng-model="model.data.contentVersion.meta.phones"
        data-options='["Main", "Mobile", "Work", "Personal"]'
        data-type="phone"
        data-custom="true"
        data-multiple="true">
    </stratus-option-value>

The label/value pairs are stored in the AssetManager, which allows for multiple dynamic fields to be attached to any entity.