Jump to content

Rikki

Members
  • Posts

    24,413
  • Joined

  • Last visited

  • Days Won

    84

Reputation Activity

  1. Like
    Rikki got a reaction from The Old Man for a guide, Adding custom editor buttons   
    If an existing CKEditor plugin isn't available that meets your needs, another alternative that may be suitable is to create a custom button.
     
    What can custom buttons do?
    Custom buttons allow you to create blocks of HTML that are inserted by clicking a button on the editor toolbar. The blocks you create can accept content that users can enter.
    Custom buttons don't have the capabilities of a full CKEditor plugin - they can't be dynamic or use Javascript, for example. But for formatting text the user enters, a custom button may be the best choice.
    Note: although custom buttons tend to be simple, we recommend you have knowledge of HTML, or seek assistance from our peer-to-peer forums.
     
    Creating a custom button
    To create a custom button, navigate to Customization -> Editor -> Toolbars. Click the Add Button button in the header, and then the Custom tab. The form you see has the following fields:
    Button title
    The title seen by users when they hover over the button in the editor Icon
    A small image file that will act at the button icon on the editor. For retina support, upload an icon twice as big as you'd like it to display; it will be resized down by the browser and therefore show high-res. Type
    Three types of content are supported, and they roughly mimic the three types of element display in HTML: Inline - used when the inserted HTML exists somewhere in a line of text. Does not create a new line for the content. Single line block - designed for single lines (e.g. headers), and puts the block on a new line Block - used for multiple lines, and puts the block on a new line Use option
    A custom button can optionally accept a value from the user (aside from what they can type as normal inside the block itself). This option will appear as a popup dialog when the user clicks the button in the editor, and the value they enter is passed into the block when it is rendered. With this field enabled, you'll see an additional setting: Option label
    The text shown to the user requesting a value for the option. HTML
    The actual HTML the button will render in the editor when used. Generally, any HTML is supported but it must be valid. Within this HTML, a couple of special tags can be used: {option}
    If the option is used, this tag is replaced with the value the user entered, as-is. {content}
    If your button will allow the user to type within the generated HTML, insert this tag where the user should be able to type. Click the Save button to create the button. Your icon will be shown on the Buttons Not On Editor toolbar, and from here you can drag it to your live toolbars and configure it as normal.
     
    Using custom styles
    We don't recommend using inline styles in your HTML, because it will be almost impossible for you to update later (posts are built at save-time, not display-time, so if you update a custom button, old posts won't reflect those changes).
    Instead, we suggest using classnames, and adding styles for those classnames in your custom.css theme file. This way, you can update the styles later, and old posts will also reflect the changes.
     
    An example
    Within this documentation we have tip boxes like this:
    Tip This is a tip
    This is a custom editor button we've created that is available to staff. Here's the configuration we used to create this button:
    Button title
    Tip Icon
    Type
    Block Use option
    No HTML <div class='docsBox docsBox_tip'> <div class='docsBox_header'>Tip</div> <div class='docsBox_body'> <div class='ipsType_richText ipsType_break ipsContained'> {content} </div> </div> </div>  
    We then add these styles to our custom.css CSS file:
    .docsBox_header { padding: 5px 10px; color: #fff; font-weight: 500; font-size: 15px; } .docsBox_body { padding: 10px; font-size: 13px; line-height: 1.4; } .docsBox_tip .docsBox_header { background: #2E7D32; } .docsBox_tip .docsBox_body { background: #E8F5E9; } .docsBox_tip .docsBox_body .ipsType_richText { color: #1B5E20; }  
  2. Like
    Rikki got a reaction from The Old Man for a guide, Targeting elements on specific pages with CSS   
    Occasionally, you'll want to be able to change the style of a particular element on a particular page, without affecting similar elements on other pages. For example, lets say you wanted to change how the .ipsPageHeader element looks in topic view, to make the title bigger, but without changing it for all other pages that also use .ipsPageHeader.
     
    Adding a classname - the wrong way
    One method would be to edit the template for topic view, add a classname to the element, and then create a style using that new classname as the selector. This works, but it has a drawback - because you've edited the template, IPS4 won't be able to automatically update it for you when you upgrade to newer versions of the IPS Community Suite. We always suggest you try and avoid editing templates directly, for this reason.
     
    Using page-specific selectors - the right way
    There's a better way - every page in IPS4 includes some special attributes on the body tag that identify the app, module and controller being viewed. You can use these to write a CSS selector to only target pages that match the ones you want. Going back to our example, we could target .ipsPageHeader in topic view like so:
    body[data-pageapp="forums"][data-pagemodule="forums"][data-pagecontroller="topic"] .ipsPageHeader { ...your styles } This works because topic view is generated by the topic controller, in the forums module, in the forums app. All pages in the IPS Community Suite follow this controller/module/application structure.
    You can mix and match these. If you want to style all page headers in the forums app only, you could simplify the above to:
    body[data-pageapp="forums"] .ipsPageHeader { ...your styles } You can find out the right values to use by going to the page you want to target, viewing the source in a tool like Web Inspector, and finding the body tag - look for the special data-page* attributes that are used for that page.
    By including these styles in your custom.css file in your theme, you can target specific elements on specific pages, without making it difficult to upgrade your community later.
  3. Like
    Rikki got a reaction from DeanW for a guide, Pages   
    The foundation of Pages (the application) is the page (the thing).
                            Tip To alleviate confusion in these tutorials, the application "Pages" will always be referred to with a capital letter; pages within the application or community will be lowercase.
    What is a page?
    A page is a container for content. Depending on your needs, a page can simply contain simple content (whether that's plain text, or rich content with images, embeds, and the other things you're used from our other applications), or more complex content like blocks and databases (see later steps to find out more about those).
    If you are comfortable with code, you can also use all of our standard template logic in a page, allowing for some highly custom results. For those who aren't comfortable with coding, there's an easy page builder, allowing you to drag and drop components into your page.
    A page has a URL, and can be automatically added to your menu navigation when you create it, if you wish.
    A page can also have custom permissions, allowing you to restrict who can or cannot access the page. This is great if you want to build special sections of your site, perhaps for staff or premium members only.
    Prior to Invision Community 4.3, Pages were not searchable (although external search engines such as Google will index them). However, if you have a database on a page, the content of the database will be searchable.
    Creating Pages
    Pages are created via the AdminCP, by navigating to Pages -> Pages. A directory listing of your current pages will be shown. Folders are supported here as you'd expect; the URL of the page will reflect this structure. For example, a page called index in a folder called guides will have the URL <your community URL>/guides/index. 
    When you click the Add Page button, you are asked whether you want to use the Page Builder or Manual HTML.

    Page Type
    Page Builder
    After creating the page in the AdminCP, you'll be able to go to the front-end to add content to your page, using drag and drop from the sidebar manager. This option is best for those not familiar with HTML. Manual HTML
    When you choose this option, you'll be provided with a code editor to create your page. Within this code editor you're free to use HTML, as well as the full range of template logic supported by IPS4. With this method, you insert other items (blocks, databases etc.) into the page by using special tags. A sidebar on the editor show you the available tags.  
    Managing content in pages with the drag and drop editor
    If you've created a page using the Page Builder options, after saving the configuration in the AdminCP, you can head over to the page on the front-end to manage its content (click the View Page option from the menu on the page listing screen to easily navigate to it). 
    By default, the page will be empty. Click the sidebar toggle to open the sidebar and see the available widgets. All of the usual widgets are available to you from across the suite, but under the Pages category are a handful of special reusable widgets:

    Block Manager
    Of these, WYSIWYG Editor is the one you'd be most likely to use when setting up your pages. It gives you a standard IPS4 rich text editor to add content to the page. Simply drag it into a location on your page, then click the Edit button to access the editor. We won't cover the other blocks here since they are specific to other kinds of functionality within Pages.
    Managing content in pages using Manual HTML
    When you create a page using manual HTML, you can choose how much of the standard IPS4 wrapper you start with. By default, the suite wrapper is included in the output. This encompasses the header, menu navigation etc., meaning the content of your page is inserted inside this wrapper. With this option disabled, the suite wrapper isn't used - you'll be responsible for providing this (you can however choose a custom page wrapper you've created).
    If you use the suite wrapper, you can also choose whether the standard sidebar is included in the output. The content you enter into the code editor forms the main page content, and the sidebar will be managed as usual with drag and drop on the front-end.
    Adding to Navigation
    When you create a page, you can easily add it to your site's main navigation menu under the Menu tab on the page edit screen. Alternatively, you can add it to the menu manually via the normal menu management process.
     
    Setting as Default
    Often you will wish to set the pages application as your default application, so that you can show a page you created as your default homepage. For this, along with how to create a basic homepage, please refer to the following guide.
      Blocks
  4. Like
    Rikki got a reaction from kyriazhs1975 for a guide, Pages   
    The foundation of Pages (the application) is the page (the thing).
                            Tip To alleviate confusion in these tutorials, the application "Pages" will always be referred to with a capital letter; pages within the application or community will be lowercase.
    What is a page?
    A page is a container for content. Depending on your needs, a page can simply contain simple content (whether that's plain text, or rich content with images, embeds, and the other things you're used from our other applications), or more complex content like blocks and databases (see later steps to find out more about those).
    If you are comfortable with code, you can also use all of our standard template logic in a page, allowing for some highly custom results. For those who aren't comfortable with coding, there's an easy page builder, allowing you to drag and drop components into your page.
    A page has a URL, and can be automatically added to your menu navigation when you create it, if you wish.
    A page can also have custom permissions, allowing you to restrict who can or cannot access the page. This is great if you want to build special sections of your site, perhaps for staff or premium members only.
    Prior to Invision Community 4.3, Pages were not searchable (although external search engines such as Google will index them). However, if you have a database on a page, the content of the database will be searchable.
    Creating Pages
    Pages are created via the AdminCP, by navigating to Pages -> Pages. A directory listing of your current pages will be shown. Folders are supported here as you'd expect; the URL of the page will reflect this structure. For example, a page called index in a folder called guides will have the URL <your community URL>/guides/index. 
    When you click the Add Page button, you are asked whether you want to use the Page Builder or Manual HTML.

    Page Type
    Page Builder
    After creating the page in the AdminCP, you'll be able to go to the front-end to add content to your page, using drag and drop from the sidebar manager. This option is best for those not familiar with HTML. Manual HTML
    When you choose this option, you'll be provided with a code editor to create your page. Within this code editor you're free to use HTML, as well as the full range of template logic supported by IPS4. With this method, you insert other items (blocks, databases etc.) into the page by using special tags. A sidebar on the editor show you the available tags.  
    Managing content in pages with the drag and drop editor
    If you've created a page using the Page Builder options, after saving the configuration in the AdminCP, you can head over to the page on the front-end to manage its content (click the View Page option from the menu on the page listing screen to easily navigate to it). 
    By default, the page will be empty. Click the sidebar toggle to open the sidebar and see the available widgets. All of the usual widgets are available to you from across the suite, but under the Pages category are a handful of special reusable widgets:

    Block Manager
    Of these, WYSIWYG Editor is the one you'd be most likely to use when setting up your pages. It gives you a standard IPS4 rich text editor to add content to the page. Simply drag it into a location on your page, then click the Edit button to access the editor. We won't cover the other blocks here since they are specific to other kinds of functionality within Pages.
    Managing content in pages using Manual HTML
    When you create a page using manual HTML, you can choose how much of the standard IPS4 wrapper you start with. By default, the suite wrapper is included in the output. This encompasses the header, menu navigation etc., meaning the content of your page is inserted inside this wrapper. With this option disabled, the suite wrapper isn't used - you'll be responsible for providing this (you can however choose a custom page wrapper you've created).
    If you use the suite wrapper, you can also choose whether the standard sidebar is included in the output. The content you enter into the code editor forms the main page content, and the sidebar will be managed as usual with drag and drop on the front-end.
    Adding to Navigation
    When you create a page, you can easily add it to your site's main navigation menu under the Menu tab on the page edit screen. Alternatively, you can add it to the menu manually via the normal menu management process.
     
    Setting as Default
    Often you will wish to set the pages application as your default application, so that you can show a page you created as your default homepage. For this, along with how to create a basic homepage, please refer to the following guide.
      Blocks
  5. Like
    Rikki got a reaction from Meddysong for a guide, Changing FontAwesome icons per-forum   
    By default, we use the 'comments' icon from FontAwesome to represent forums on the read/unread badges. IPS4 also includes an option to upload an image that will be used instead of the icon. But what if you want to use a different FontAwesome icon for each forum?
    The good news is this is possible using some custom CSS. Each forum row in the index template includes a data attribute with the forum ID, meaning we can write a style to specifically target each individual forum and overwrite the icon it uses.
    Note: Although this method isn't terribly complex, it does require editing custom CSS and working with unicode characters.
     
    Determining the icon unicode value
    The method we're going to use involves replacing the icon using a CSS rule, rather than changing the icon classname in the HTML. The reason we take this approach is it won't make upgrading your templates difficult later - our custom CSS persist through IPS4 versions easily.
    What this means however is that we need to identify the unicode value that FontAwesome assigns to the icons we want to use.
    To do so, head over to the FontAwesome icon list on this page. Locate the icon you'd like to use, and click it. On the information page, you'll see the unicode value for the icon. Make a note of this code. For example:

    Do this for each icon you'll want to use.
     
    Adding the CSS
    We're going to add our CSS to our custom.css file so that it persists through upgrades. In the AdminCP, go to Customizations -> Themes, and click the code edit icon next to the theme you want to change. On the CSS tab, open the custom.css file:

    The rule we need to use looks like this:
    [data-forumid="..."] .fa-comments:before { content: "\f123"; } You'll need to adjust this code to include the forum ID for the forum you want to change. You can find the forum ID by hovering on the link to the forum, and noting the number you see in the URL: 

    You'll also need to replace the f123 unicode value with the one for the icon you want to use that you noted earlier.
     
    Example
    Let's say we have forum ID's 1 and 2, and we want to use FontAwesome's bicycle and car icons, respectively. We note the unicode values for those icons, which are f206 and f1b9.
    The CSS we'd add looks like this:
    [data-forumid="1"] .fa-comments:before { content: "\f206"; } [data-forumid="2"] .fa-comments:before { content: "\f1b9"; } Once we save it, we can see the result:

  6. Like
    Rikki got a reaction from kar3n2 for a guide, Adding custom fields   
    Custom fields are what you use to make a database that is specific to your needs. IPS4 supports a wide range of field types so that you can collect data in the appropriate formats, from text and numbers, to upload fields and YouTube embeds.
    We're going to create a few different fields to gather information about each recipe that we can then display in our database. They are:
    List of ingredients Prep time Cook time Cuisine A link to a YouTube video recipe We don't need fields for the recipe title, or the instructions. Databases already provide a title field, and we'll also use the built-in content field for the recipe instructions.
    We'll see how to set up the custom fields, as well as how to customize their appearance.
     
    Ingredients field
    1. To create a new field, hover on the Pages tab in the AdminCP, and then click the Fields link under the Recipes database in the menu. The screen will show you the default built-in fields for your database, including Title and Content.
    2. Click the Create New button; you'll see a form where you configure your field.
    3. For Title, enter "Ingredients". This is the field title users will see when adding/viewing recipes on your site.
    4. For Description, enter "One per line". The description is only shown on the add/edit record form, so it's a good place to enter special instructions for filling it in.
    5. For the type, we'll choose Editor in this case, because it will allow the user to format the list if they wish. The other fields on the form will change depending on which field type you choose, since each has specific options.
    6. We don't require a maximum length, but we do want to require this field to be completed, so leave these settings at their default values.
    7. On the Display tab, we'll configure how the field content is shown to users. First, enter ingredients as the field key. This key is how IPS4 identifies this field in templates. We won't actually be using it in this tutorial, but it's good practice to set it anyway so you can use it later if needed.
    8. We don't want our list of ingredients to show on the listing screen, so disable that option.
    9. We do, however, want it to show on the record display screen, since this is the main screen for viewing a recipe. A badge isn't ideal for showing content from an Editor, so change the Display View Format to the simple Label: Value option as shown:

    Display View Format
    10. We'll show the list of ingredients above the main record content, so make sure Above the item content is selected for the Display option.
    11. Finally, there's no need to allow this field to be updated when viewing a record; instead, users will go to the full edit form. You can leave the Editable when viewing a record option disabled.
    12. Save the form to create the field.
     
    Other fields
    Other fields
    Other fields are created in the same way, so instead of going through the whole process again, here's the configuration options you need for each field. Where a configuration option isn't listed, leave it at its default value.
    Note: Some field types, including the Select Box type that Cuisine uses (see below), support a fixed set of options from which the user can choose. You'll set these up as key/value pairs in the AdminCP, but the user will only see the values when they select them. The key is just used internally by IPS4 and in custom templates to identify the value, and is best kept as a single lowercase word.
     
    Prep time
    Name: Prep Time
    Type: Text
    Required: No
    Template key: prep-time
    Listing view format: Label: Value
    Display view format: Label: Value
     
    Cook time
    Name: Cook Time
    Type: Text
    Required: No
    Template key: cook-time
    Listing view format: Label: Value
    Display view format: Label: Value
     
    Cuisine
    Name: Cuisine
    Type: Select Box
    Content: (key/value)
    indian / Indian italian / Italian american / American mexican / Mexican Allow filtering: Yes
    Required: Yes
    Template key: cuisine
    Listing view format: Label: Value
    Show to right of listing area: Yes
    Display view format: Label: Value
    Display: Above the item content
     
    Video recipe
    Name: Video tutorial
    Type: YouTube Embed
    Required: No
    Template key: video-tutorial
    Show in listing template: No
    Show in display template: Yes
    In a record, display as: Embedded Player
     
    That's it! If you now head over to the front-end page for your database, click into a category, and click the Add New Recipe button, you'll see your fields on the form, ready to collect information! Feel free to add some sample records to try it out.
    You'll also see the Record Image field that the database provides automatically (discussed earlier). When you upload an image here, you'll see it is automatically included in the record view for you.
    Here's an example recipe in our database:

    Listing View

    Record View
  7. Like
    Rikki got a reaction from sobrenome for a guide, ips.ui.dialog   
    Description
    The dialog widget displays popup windows within the page, typically loading content from a remote source.
     
    Usage
    A dialog is defined simply by including the widget key as an attribute on a trigger element. It is recommended that the trigger element be a link or button, so that if the user has javascript disabled their browser can take them to a full-page version of the dialog contents.
    <a href='...' data-ipsDialog data-ipsDialog-url='...'>Launch dialog</a> Dialogs offer special functionality for forms contained with the dialog, enabling them to be automatically validated and submitted via AJAX when used with the form helper from the IPS4 PHP framework. See the remoteVerify and remoteSubmit options below.
     
    Obtaining a dialog reference
    If you need to control a dialog programmatically, you can do so by first obtaining the reference to the dialog. To do so, call the getObj method, passing in the element on which the dialog was created as the parameter:
    // HTML <div id='elementWithDialog' data-ipsDialog> ... </div> // Javascript var dialog = ips.ui.dialog.getObj( $('#elementWithDialog') ); The returned reference to the dialog instance can be used to call the methods shown below.
     
    Creating a dialog programmatically
    Dialogs can be created programmatically by controllers instead of being created on particular elements. To achieve this, call the create method:
    var dialog = ips.ui.dialog.create( object options ); The options parameter should be an object containing keys for the options below.
    This method returns a reference to the dialog instance on which you can call methods to control the dialog, for example:
    dialog.show(); dialog.hide();  
    Instance methods
    show( boolean initOnly )
    Initializes and shows the dialog. If initOnly is true, the dialog is initialized but not immediately shown.
     
    hide()
    Hides the dialog.
     
    remove( boolean hideFirst )
    Removes the dialog from the DOM. If hideFirst is true, the dialog will call hide() and remove itself after the animation is completed.
     
    setLoading( boolean loading )
    If loading is true, indicates to the user that something is being loaded (i.e. shows a spinner in the dialog). If loading is false, removes the loading state. Note: this method doesn't empty the dialog content first. Call instance.updateContent('') manually if desired.
     
    updateContent( string newContent )
    Updates the contents of the dialog with the provided newContent. New controllers/widgets are automatically initialized after updating.
     
    Options
    url
    (String; optional)
    If provided, the dialog contents will be loaded by calling this URL when the dialog is launched.
     
    content
    (Selector; optional)
    If the dialog content already exists in the DOM, this option should be a selector that will locate the wrapper element for the content.
     
    modal
    (Boolean; optional; default true)
    If true, the page background will fade, preventing the user from interacting with it until the dialog is dismissed.
     
    title
    (String; optional)
    Sets the title shown in the dialog window. If not set, no title bar will display.
     
    size
    (String; optional)
    If provided, will set a special class on the dialog designed to change its size. Currently, narrow, medium, wide and fullscreen are supported as values for this option. If not provided, the default dialog width will be used (defined in CSS).
     
    close
    (Boolean; optional; default true)
    Determines whether the dialog should be built with a close button.
     
    fixed
    (Boolean; optional; default false)
    Determines whether the dialog is fixed. A fixed dialog is anchored to the viewport, not the page. Its height will also be fixed, with the content scrolling inside if necessary. If this is false, the dialog will scroll with the page, and it will expand to fit all the content being shown, regardless of length.
     
    remoteVerify
    (Boolean; optional; default true)
    When the dialog contains a form built using the IPS4 PHP framework form helper, this option instructs the dialog to automatically validate the form values and present any errors to the user.
     
    remoteSubmit
    (Boolean; optional; default false)
    When the dialog contains a form built using the IPS4 PHP framework form helper, this option instructs the dialog to submit the form values via AJAX. If remoteVerify is also true, two separate AJAX requests are fired; first, the form is validated, and if successful the form is submitted with a second request.
    If remoteSubmit is true, after a successful submit the dialog is closed automatically. If the flashMessage option is provided, it will be shown at this point.
    By default, remoteSubmit is false, which means forms submit via a traditional page reload.
     
    callback
    (Function; optional)
    Specifies a callback function that will be executed after the dialog has loaded remote content. Note: this option cannot be provided via the data API, and is therefore only available when interacting with ips.ui.dialog directly.
     
    forceReload
    (Boolean; optional; default false)
    By default, once a dialog has loaded its content, it will not do so again even if the dialog is relaunched. By setting this option to true, the dialog will call the url every time it is opened. This option only takes effect when the url option is used.
     
    Events emitted by ips.ui.dialog
    openDialog
    Triggered when the dialog is shown.
    Event data:
    elemID
    ID of the element that triggered the dialog dialogID
    ID of the dialog element dialog
    Reference to the dialog element contentLoaded
    Boolean indicating whether the dialog content has been loaded (may be false if remote content is used)  
    hideDialog
    Triggered when the dialog is hidden.
    Event data:
    elemID
    ID of the element that triggered the dialog dialogID
    ID of the dialog element dialog
    Reference to the dialog element  
    dialogContentLoaded
    Triggered after remote content has been loaded and inserted into the dialog.
    Event data:
    elemID
    ID of the element that triggered the dialog dialogID
    ID of the dialog element dialog
    Reference to the dialog element contentLoaded
    Boolean indicating whether the dialog content has been loaded (always true here)  
    Events to which ips.ui.dialog responds
    closeDialog
    Instructs the dialog to close.
    Event data:
    dialogID (required)
    The ID of the dialog to close (the event is ignored if the ID does not match the current dialog)
     
  8. Like
    Rikki got a reaction from sobrenome for a guide, Dropdown Menus   
    Description
    Dropdown menus allow users to select from a number of options. The markup is designed to work in tandem with the ips.ui.menu javascript module.
     
    Usage
    A menu consists of a trigger element, and the menu element itself:
    <!-- The trigger --> <a href='#elMyMenu_menu' id='elMyMenu'>Open Menu</a> <!-- The menu --> <ul id='elMyMenu_menu' class='ipsMenu'> ... </ul> The ID of the menu should be the ID of the trigger element, suffixed by _menu. If the trigger element is a link, its href should be an anchor to the ID of the menu element. This makes the menu accessible even when Javascript is disabled in the browser.
     
    Basic menu
    A basic menu might have the following markup:
    <ul class='ipsMenu ipsHide'> <li class='ipsMenu_item'><a href='#'>Item 1</a></li> <li class='ipsMenu_item'><a href='#'>Item 2</a></li> <li class='ipsMenu_item'><a href='#'>Item 3</a></li> <li class='ipsMenu_sep'><hr></li> <li class='ipsMenu_item'><a href='#'>Item 4</a></li> <li class='ipsMenu_item'><a href='#'>Item 5</a></li> </ul> This would display as follows: see example.
    Item 1 Item 2 Item 3 Item 4 Item 5 ipsMenu is the base class for the menu element. Items within the menu should have the class ipsMenu_item, with the link element inside of that. A separator item can be added by giving the item the class ipsMenu_sep, containing an <hr> element.
    Note that the positioning and stem is added automatically by the menu javascript module; it does not need to be manually specified. The stem can be removed, if necessary, by including the class ipsMenu_noStem on the menu element.
     
    Disabling menu items
    Individual menu items can be disabled by adding the class ipsMenu_itemDisabled to the list item: see example.
    Item 1 Disabled Item 2 Item 3 Note: Disabled items are not foolproof; in browsers that do not support the CSS pointer-events style, a click on a disabled item will still register. Ensure your javascript properly deals with disabled item clicks if necessary.
     
    Menu sizing
    By default, a menu will have no defined width. An additional classname can be specified on the menu element to determine how wide it should display.
    ipsMenu_auto - menu will appear as wide as necessary, though with a minimum width of 200px and a maximum width of 500px ipsMenu_narrow - 200 pixels wide ipsMenu_normal - 300 pixels wide ipsMenu_wide - 450 pixels wide  
    Selectable menus
    A selectable menu allows the user to toggle one or more of the menu items, useful for turning options on and off. For this functionality to work, the javascript module needs to be used.
    A menu can be made selectable by adding the classname ipsMenu_selectable. A menu item can be shown as selected by adding the classname ipsMenu_itemChecked to the list item.
    The markup for a selectable menu might look this:
    <ul id='elMenu2_menu' class='ipsMenu ipsMenu_normal ipsMenu_selectable ipsHide'> <li class='ipsMenu_item'><a href='#'>Item 1</a></li> <li class='ipsMenu_item ipsMenu_itemChecked'><a href='#'>Item 2</a></li> <li class='ipsMenu_item'><a href='#'>Item 3</a></li> </ul> This would display as follows: see example.
    Item 1 Item 2 Item 3  
    Sub-menus
    Submenus can be created by embedding menus within one another. To do so, simply include the ipsMenu_subItems class on the item that contains the submenu, and the submenu itself within the item. For example:
    <ul id='elMenu3_menu' class='ipsMenu ipsMenu_normal ipsHide'> <li class='ipsMenu_item'> <a href='#'>Item 1 (no children)</a> </li> <li class='ipsMenu_item ipsMenu_subItems'> <a href='#'>Item 2 (with children)</a> <ul class='ipsMenu ipsMenu_wide ipsHide'> <li class='ipsMenu_item'><a href='#'>Sub Item 1</a></li> <li class='ipsMenu_item'><a href='#'>Sub Item 2</a></li> <li class='ipsMenu_item'><a href='#'>Sub Item 3</a></li> </ul> </li> </ul> This would display as follows: see example.
    Item 1 (no children) Item 2 (with children) Sub Item 1 Sub Item 2 Sub Item 3  
  9. Like
    Rikki got a reaction from sobrenome for a guide, (Advanced) Building dynamic blocks based on the page being viewed   
    For more advanced sites built with Pages, you may want to change the output of a custom HTML or PHP block depending on which page the user is viewing. For example, if you have a custom menu, you may want to highlight the active item.
    We can implement this in Pages by checking the underlying page URL parameters. Although you access a page with a friendly URL (FURL) like http://<yourcommunity>/section/page, behind the scenes this is mapped to a raw URL, such as http://<yourcommunity>/index.php?app=cms&module=pages&controller=page&path=/section/page. Notice the path parameter allows us to identify which page we're accessing. When we access the \IPS\Request::i() object, we can compare against this parameter, like so:
    {{if strpos( \IPS\Request::i()->path, 'section/page' ) !== FALSE}} <!-- We know the user is on /section/page --> {{elseif strpos( \IPS\Request::i()->path, 'othersection/otherpage' ) !== FALSE}} <!-- We know the user is on /othersection/otherpage --> {{endif}} Note that for reliability, we're using PHP's strpos function to check for the presence of the page URL in the path parameter, rather than a simple comparison.
    Example
    Let's assume we've created a Manual HTML block, we're adding HTML to show a menu, and we want to highlight the correct item based on the page. Here's what our block contents might look like:
    <ul class='ipsList_inline cMyMenu'> <li {{if strpos( \IPS\Request::i()->path, 'help/home' ) !== FALSE}}class='active'{{endif}}> <a href='/help/home'>Home</a> </li> <li {{if strpos( \IPS\Request::i()->path, 'help/faq' ) !== FALSE}}class='active'{{endif}}> <a href='/help/faq'>FAQ</a> </li> <li {{if strpos( \IPS\Request::i()->path, 'help/tutorials' ) !== FALSE}}class='active'{{endif}}> <a href='/help/tutorials'>Tutorials</a> </li> </ul> If we had many items to show, it would get tedious to list them all like this. We could instead do it as a loop:
    // Using a PHP variable to store an array of pages => page names that we'll loop over {{$myPages = array('help/home' => "Home", 'help/faq' => "FAQ", 'help/tutorials' => "Tutorials", 'help/qna/listing' => "Questions", 'help/qna/recent' => "Recent Questions", 'help/contact' => "Contact Us");}} <ul class='ipsList_inline cMyMenu'> {{foreach $myPages as $url => $title}} <li {{if strpos( \IPS\Request::i()->path, $url ) !== FALSE}}class='active'{{endif}}> <a href='{$url}'>{$title}</a> </li> {{endforeach}} </ul> Now to add new items to our custom menu, we just have to add them to the array.
  10. Like
    Rikki got a reaction from MelanieWildman for a guide, Adding custom fields   
    Custom fields are what you use to make a database that is specific to your needs. IPS4 supports a wide range of field types so that you can collect data in the appropriate formats, from text and numbers, to upload fields and YouTube embeds.
    We're going to create a few different fields to gather information about each recipe that we can then display in our database. They are:
    List of ingredients Prep time Cook time Cuisine A link to a YouTube video recipe We don't need fields for the recipe title, or the instructions. Databases already provide a title field, and we'll also use the built-in content field for the recipe instructions.
    We'll see how to set up the custom fields, as well as how to customize their appearance.
     
    Ingredients field
    1. To create a new field, hover on the Pages tab in the AdminCP, and then click the Fields link under the Recipes database in the menu. The screen will show you the default built-in fields for your database, including Title and Content.
    2. Click the Create New button; you'll see a form where you configure your field.
    3. For Title, enter "Ingredients". This is the field title users will see when adding/viewing recipes on your site.
    4. For Description, enter "One per line". The description is only shown on the add/edit record form, so it's a good place to enter special instructions for filling it in.
    5. For the type, we'll choose Editor in this case, because it will allow the user to format the list if they wish. The other fields on the form will change depending on which field type you choose, since each has specific options.
    6. We don't require a maximum length, but we do want to require this field to be completed, so leave these settings at their default values.
    7. On the Display tab, we'll configure how the field content is shown to users. First, enter ingredients as the field key. This key is how IPS4 identifies this field in templates. We won't actually be using it in this tutorial, but it's good practice to set it anyway so you can use it later if needed.
    8. We don't want our list of ingredients to show on the listing screen, so disable that option.
    9. We do, however, want it to show on the record display screen, since this is the main screen for viewing a recipe. A badge isn't ideal for showing content from an Editor, so change the Display View Format to the simple Label: Value option as shown:

    Display View Format
    10. We'll show the list of ingredients above the main record content, so make sure Above the item content is selected for the Display option.
    11. Finally, there's no need to allow this field to be updated when viewing a record; instead, users will go to the full edit form. You can leave the Editable when viewing a record option disabled.
    12. Save the form to create the field.
     
    Other fields
    Other fields
    Other fields are created in the same way, so instead of going through the whole process again, here's the configuration options you need for each field. Where a configuration option isn't listed, leave it at its default value.
    Note: Some field types, including the Select Box type that Cuisine uses (see below), support a fixed set of options from which the user can choose. You'll set these up as key/value pairs in the AdminCP, but the user will only see the values when they select them. The key is just used internally by IPS4 and in custom templates to identify the value, and is best kept as a single lowercase word.
     
    Prep time
    Name: Prep Time
    Type: Text
    Required: No
    Template key: prep-time
    Listing view format: Label: Value
    Display view format: Label: Value
     
    Cook time
    Name: Cook Time
    Type: Text
    Required: No
    Template key: cook-time
    Listing view format: Label: Value
    Display view format: Label: Value
     
    Cuisine
    Name: Cuisine
    Type: Select Box
    Content: (key/value)
    indian / Indian italian / Italian american / American mexican / Mexican Allow filtering: Yes
    Required: Yes
    Template key: cuisine
    Listing view format: Label: Value
    Show to right of listing area: Yes
    Display view format: Label: Value
    Display: Above the item content
     
    Video recipe
    Name: Video tutorial
    Type: YouTube Embed
    Required: No
    Template key: video-tutorial
    Show in listing template: No
    Show in display template: Yes
    In a record, display as: Embedded Player
     
    That's it! If you now head over to the front-end page for your database, click into a category, and click the Add New Recipe button, you'll see your fields on the form, ready to collect information! Feel free to add some sample records to try it out.
    You'll also see the Record Image field that the database provides automatically (discussed earlier). When you upload an image here, you'll see it is automatically included in the record view for you.
    Here's an example recipe in our database:

    Listing View

    Record View
  11. Like
    Rikki got a reaction from Meddysong for a guide, Dropdown Menus   
    Description
    Dropdown menus allow users to select from a number of options. The markup is designed to work in tandem with the ips.ui.menu javascript module.
     
    Usage
    A menu consists of a trigger element, and the menu element itself:
    <!-- The trigger --> <a href='#elMyMenu_menu' id='elMyMenu'>Open Menu</a> <!-- The menu --> <ul id='elMyMenu_menu' class='ipsMenu'> ... </ul> The ID of the menu should be the ID of the trigger element, suffixed by _menu. If the trigger element is a link, its href should be an anchor to the ID of the menu element. This makes the menu accessible even when Javascript is disabled in the browser.
     
    Basic menu
    A basic menu might have the following markup:
    <ul class='ipsMenu ipsHide'> <li class='ipsMenu_item'><a href='#'>Item 1</a></li> <li class='ipsMenu_item'><a href='#'>Item 2</a></li> <li class='ipsMenu_item'><a href='#'>Item 3</a></li> <li class='ipsMenu_sep'><hr></li> <li class='ipsMenu_item'><a href='#'>Item 4</a></li> <li class='ipsMenu_item'><a href='#'>Item 5</a></li> </ul> This would display as follows: see example.
    Item 1 Item 2 Item 3 Item 4 Item 5 ipsMenu is the base class for the menu element. Items within the menu should have the class ipsMenu_item, with the link element inside of that. A separator item can be added by giving the item the class ipsMenu_sep, containing an <hr> element.
    Note that the positioning and stem is added automatically by the menu javascript module; it does not need to be manually specified. The stem can be removed, if necessary, by including the class ipsMenu_noStem on the menu element.
     
    Disabling menu items
    Individual menu items can be disabled by adding the class ipsMenu_itemDisabled to the list item: see example.
    Item 1 Disabled Item 2 Item 3 Note: Disabled items are not foolproof; in browsers that do not support the CSS pointer-events style, a click on a disabled item will still register. Ensure your javascript properly deals with disabled item clicks if necessary.
     
    Menu sizing
    By default, a menu will have no defined width. An additional classname can be specified on the menu element to determine how wide it should display.
    ipsMenu_auto - menu will appear as wide as necessary, though with a minimum width of 200px and a maximum width of 500px ipsMenu_narrow - 200 pixels wide ipsMenu_normal - 300 pixels wide ipsMenu_wide - 450 pixels wide  
    Selectable menus
    A selectable menu allows the user to toggle one or more of the menu items, useful for turning options on and off. For this functionality to work, the javascript module needs to be used.
    A menu can be made selectable by adding the classname ipsMenu_selectable. A menu item can be shown as selected by adding the classname ipsMenu_itemChecked to the list item.
    The markup for a selectable menu might look this:
    <ul id='elMenu2_menu' class='ipsMenu ipsMenu_normal ipsMenu_selectable ipsHide'> <li class='ipsMenu_item'><a href='#'>Item 1</a></li> <li class='ipsMenu_item ipsMenu_itemChecked'><a href='#'>Item 2</a></li> <li class='ipsMenu_item'><a href='#'>Item 3</a></li> </ul> This would display as follows: see example.
    Item 1 Item 2 Item 3  
    Sub-menus
    Submenus can be created by embedding menus within one another. To do so, simply include the ipsMenu_subItems class on the item that contains the submenu, and the submenu itself within the item. For example:
    <ul id='elMenu3_menu' class='ipsMenu ipsMenu_normal ipsHide'> <li class='ipsMenu_item'> <a href='#'>Item 1 (no children)</a> </li> <li class='ipsMenu_item ipsMenu_subItems'> <a href='#'>Item 2 (with children)</a> <ul class='ipsMenu ipsMenu_wide ipsHide'> <li class='ipsMenu_item'><a href='#'>Sub Item 1</a></li> <li class='ipsMenu_item'><a href='#'>Sub Item 2</a></li> <li class='ipsMenu_item'><a href='#'>Sub Item 3</a></li> </ul> </li> </ul> This would display as follows: see example.
    Item 1 (no children) Item 2 (with children) Sub Item 1 Sub Item 2 Sub Item 3  
  12. Like
    Rikki got a reaction from MMahdiD25 for a guide, Pages   
    The foundation of Pages (the application) is the page (the thing).
                            Tip To alleviate confusion in these tutorials, the application "Pages" will always be referred to with a capital letter; pages within the application or community will be lowercase.
    What is a page?
    A page is a container for content. Depending on your needs, a page can simply contain simple content (whether that's plain text, or rich content with images, embeds, and the other things you're used from our other applications), or more complex content like blocks and databases (see later steps to find out more about those).
    If you are comfortable with code, you can also use all of our standard template logic in a page, allowing for some highly custom results. For those who aren't comfortable with coding, there's an easy page builder, allowing you to drag and drop components into your page.
    A page has a URL, and can be automatically added to your menu navigation when you create it, if you wish.
    A page can also have custom permissions, allowing you to restrict who can or cannot access the page. This is great if you want to build special sections of your site, perhaps for staff or premium members only.
    Prior to Invision Community 4.3, Pages were not searchable (although external search engines such as Google will index them). However, if you have a database on a page, the content of the database will be searchable.
    Creating Pages
    Pages are created via the AdminCP, by navigating to Pages -> Pages. A directory listing of your current pages will be shown. Folders are supported here as you'd expect; the URL of the page will reflect this structure. For example, a page called index in a folder called guides will have the URL <your community URL>/guides/index. 
    When you click the Add Page button, you are asked whether you want to use the Page Builder or Manual HTML.

    Page Type
    Page Builder
    After creating the page in the AdminCP, you'll be able to go to the front-end to add content to your page, using drag and drop from the sidebar manager. This option is best for those not familiar with HTML. Manual HTML
    When you choose this option, you'll be provided with a code editor to create your page. Within this code editor you're free to use HTML, as well as the full range of template logic supported by IPS4. With this method, you insert other items (blocks, databases etc.) into the page by using special tags. A sidebar on the editor show you the available tags.  
    Managing content in pages with the drag and drop editor
    If you've created a page using the Page Builder options, after saving the configuration in the AdminCP, you can head over to the page on the front-end to manage its content (click the View Page option from the menu on the page listing screen to easily navigate to it). 
    By default, the page will be empty. Click the sidebar toggle to open the sidebar and see the available widgets. All of the usual widgets are available to you from across the suite, but under the Pages category are a handful of special reusable widgets:

    Block Manager
    Of these, WYSIWYG Editor is the one you'd be most likely to use when setting up your pages. It gives you a standard IPS4 rich text editor to add content to the page. Simply drag it into a location on your page, then click the Edit button to access the editor. We won't cover the other blocks here since they are specific to other kinds of functionality within Pages.
    Managing content in pages using Manual HTML
    When you create a page using manual HTML, you can choose how much of the standard IPS4 wrapper you start with. By default, the suite wrapper is included in the output. This encompasses the header, menu navigation etc., meaning the content of your page is inserted inside this wrapper. With this option disabled, the suite wrapper isn't used - you'll be responsible for providing this (you can however choose a custom page wrapper you've created).
    If you use the suite wrapper, you can also choose whether the standard sidebar is included in the output. The content you enter into the code editor forms the main page content, and the sidebar will be managed as usual with drag and drop on the front-end.
    Adding to Navigation
    When you create a page, you can easily add it to your site's main navigation menu under the Menu tab on the page edit screen. Alternatively, you can add it to the menu manually via the normal menu management process.
     
    Setting as Default
    Often you will wish to set the pages application as your default application, so that you can show a page you created as your default homepage. For this, along with how to create a basic homepage, please refer to the following guide.
      Blocks
  13. Like
    Rikki got a reaction from BomAle for a guide, ips.ui.dialog   
    Description
    The dialog widget displays popup windows within the page, typically loading content from a remote source.
     
    Usage
    A dialog is defined simply by including the widget key as an attribute on a trigger element. It is recommended that the trigger element be a link or button, so that if the user has javascript disabled their browser can take them to a full-page version of the dialog contents.
    <a href='...' data-ipsDialog data-ipsDialog-url='...'>Launch dialog</a> Dialogs offer special functionality for forms contained with the dialog, enabling them to be automatically validated and submitted via AJAX when used with the form helper from the IPS4 PHP framework. See the remoteVerify and remoteSubmit options below.
     
    Obtaining a dialog reference
    If you need to control a dialog programmatically, you can do so by first obtaining the reference to the dialog. To do so, call the getObj method, passing in the element on which the dialog was created as the parameter:
    // HTML <div id='elementWithDialog' data-ipsDialog> ... </div> // Javascript var dialog = ips.ui.dialog.getObj( $('#elementWithDialog') ); The returned reference to the dialog instance can be used to call the methods shown below.
     
    Creating a dialog programmatically
    Dialogs can be created programmatically by controllers instead of being created on particular elements. To achieve this, call the create method:
    var dialog = ips.ui.dialog.create( object options ); The options parameter should be an object containing keys for the options below.
    This method returns a reference to the dialog instance on which you can call methods to control the dialog, for example:
    dialog.show(); dialog.hide();  
    Instance methods
    show( boolean initOnly )
    Initializes and shows the dialog. If initOnly is true, the dialog is initialized but not immediately shown.
     
    hide()
    Hides the dialog.
     
    remove( boolean hideFirst )
    Removes the dialog from the DOM. If hideFirst is true, the dialog will call hide() and remove itself after the animation is completed.
     
    setLoading( boolean loading )
    If loading is true, indicates to the user that something is being loaded (i.e. shows a spinner in the dialog). If loading is false, removes the loading state. Note: this method doesn't empty the dialog content first. Call instance.updateContent('') manually if desired.
     
    updateContent( string newContent )
    Updates the contents of the dialog with the provided newContent. New controllers/widgets are automatically initialized after updating.
     
    Options
    url
    (String; optional)
    If provided, the dialog contents will be loaded by calling this URL when the dialog is launched.
     
    content
    (Selector; optional)
    If the dialog content already exists in the DOM, this option should be a selector that will locate the wrapper element for the content.
     
    modal
    (Boolean; optional; default true)
    If true, the page background will fade, preventing the user from interacting with it until the dialog is dismissed.
     
    title
    (String; optional)
    Sets the title shown in the dialog window. If not set, no title bar will display.
     
    size
    (String; optional)
    If provided, will set a special class on the dialog designed to change its size. Currently, narrow, medium, wide and fullscreen are supported as values for this option. If not provided, the default dialog width will be used (defined in CSS).
     
    close
    (Boolean; optional; default true)
    Determines whether the dialog should be built with a close button.
     
    fixed
    (Boolean; optional; default false)
    Determines whether the dialog is fixed. A fixed dialog is anchored to the viewport, not the page. Its height will also be fixed, with the content scrolling inside if necessary. If this is false, the dialog will scroll with the page, and it will expand to fit all the content being shown, regardless of length.
     
    remoteVerify
    (Boolean; optional; default true)
    When the dialog contains a form built using the IPS4 PHP framework form helper, this option instructs the dialog to automatically validate the form values and present any errors to the user.
     
    remoteSubmit
    (Boolean; optional; default false)
    When the dialog contains a form built using the IPS4 PHP framework form helper, this option instructs the dialog to submit the form values via AJAX. If remoteVerify is also true, two separate AJAX requests are fired; first, the form is validated, and if successful the form is submitted with a second request.
    If remoteSubmit is true, after a successful submit the dialog is closed automatically. If the flashMessage option is provided, it will be shown at this point.
    By default, remoteSubmit is false, which means forms submit via a traditional page reload.
     
    callback
    (Function; optional)
    Specifies a callback function that will be executed after the dialog has loaded remote content. Note: this option cannot be provided via the data API, and is therefore only available when interacting with ips.ui.dialog directly.
     
    forceReload
    (Boolean; optional; default false)
    By default, once a dialog has loaded its content, it will not do so again even if the dialog is relaunched. By setting this option to true, the dialog will call the url every time it is opened. This option only takes effect when the url option is used.
     
    Events emitted by ips.ui.dialog
    openDialog
    Triggered when the dialog is shown.
    Event data:
    elemID
    ID of the element that triggered the dialog dialogID
    ID of the dialog element dialog
    Reference to the dialog element contentLoaded
    Boolean indicating whether the dialog content has been loaded (may be false if remote content is used)  
    hideDialog
    Triggered when the dialog is hidden.
    Event data:
    elemID
    ID of the element that triggered the dialog dialogID
    ID of the dialog element dialog
    Reference to the dialog element  
    dialogContentLoaded
    Triggered after remote content has been loaded and inserted into the dialog.
    Event data:
    elemID
    ID of the element that triggered the dialog dialogID
    ID of the dialog element dialog
    Reference to the dialog element contentLoaded
    Boolean indicating whether the dialog content has been loaded (always true here)  
    Events to which ips.ui.dialog responds
    closeDialog
    Instructs the dialog to close.
    Event data:
    dialogID (required)
    The ID of the dialog to close (the event is ignored if the ID does not match the current dialog)
     
  14. Like
    Rikki got a reaction from Meddysong for a guide, (Advanced) Building dynamic blocks based on the page being viewed   
    For more advanced sites built with Pages, you may want to change the output of a custom HTML or PHP block depending on which page the user is viewing. For example, if you have a custom menu, you may want to highlight the active item.
    We can implement this in Pages by checking the underlying page URL parameters. Although you access a page with a friendly URL (FURL) like http://<yourcommunity>/section/page, behind the scenes this is mapped to a raw URL, such as http://<yourcommunity>/index.php?app=cms&module=pages&controller=page&path=/section/page. Notice the path parameter allows us to identify which page we're accessing. When we access the \IPS\Request::i() object, we can compare against this parameter, like so:
    {{if strpos( \IPS\Request::i()->path, 'section/page' ) !== FALSE}} <!-- We know the user is on /section/page --> {{elseif strpos( \IPS\Request::i()->path, 'othersection/otherpage' ) !== FALSE}} <!-- We know the user is on /othersection/otherpage --> {{endif}} Note that for reliability, we're using PHP's strpos function to check for the presence of the page URL in the path parameter, rather than a simple comparison.
    Example
    Let's assume we've created a Manual HTML block, we're adding HTML to show a menu, and we want to highlight the correct item based on the page. Here's what our block contents might look like:
    <ul class='ipsList_inline cMyMenu'> <li {{if strpos( \IPS\Request::i()->path, 'help/home' ) !== FALSE}}class='active'{{endif}}> <a href='/help/home'>Home</a> </li> <li {{if strpos( \IPS\Request::i()->path, 'help/faq' ) !== FALSE}}class='active'{{endif}}> <a href='/help/faq'>FAQ</a> </li> <li {{if strpos( \IPS\Request::i()->path, 'help/tutorials' ) !== FALSE}}class='active'{{endif}}> <a href='/help/tutorials'>Tutorials</a> </li> </ul> If we had many items to show, it would get tedious to list them all like this. We could instead do it as a loop:
    // Using a PHP variable to store an array of pages => page names that we'll loop over {{$myPages = array('help/home' => "Home", 'help/faq' => "FAQ", 'help/tutorials' => "Tutorials", 'help/qna/listing' => "Questions", 'help/qna/recent' => "Recent Questions", 'help/contact' => "Contact Us");}} <ul class='ipsList_inline cMyMenu'> {{foreach $myPages as $url => $title}} <li {{if strpos( \IPS\Request::i()->path, $url ) !== FALSE}}class='active'{{endif}}> <a href='{$url}'>{$title}</a> </li> {{endforeach}} </ul> Now to add new items to our custom menu, we just have to add them to the array.
  15. Like
    Rikki got a reaction from Josh Bond for a guide, Template plugins   
    It's often useful to transform raw values in some way, and this is achieved in IPS4 with template plugins. Template plugins take a value, and optionally some arguments, and output some transformed value.
    The syntax for template tags is:
    {pluginkey="<value>" argument="..."} The value can be a normal string, or it could be a variable coming from elsewhere.
    Template plugins can always be used in templates, but some can also be used in CSS files. Those that can are identified below.
     
    Available plugins
    {advertisement="$location"}
    The HTML for the specified ad location
    Parameters
    $location - A valid advertisement location
     
    {datetime="$timestamp" dateonly="[boolean]" norelative="[boolean]" lowercase="[boolean]" short="[boolean]"}
    Shows a time formatted according to the user's locale
    Parameters
    $timestamp - A timestamp to transform into a date
    dateonly - Show only the date (with no time)
    norelative - By default, relative times will be used (e.g. 8 hours ago). To always show an absolute date/time, set this to true.
    lowercase - By default, date strings will be capitalized where necessary (e.g. Yesterday, 8:32pm). Setting this to true ensures it is lowercase, for use in a sentence.
    short - Uses a very short date format (ideal for mobile devices)
     
    {expression="$expression" raw="[boolean]"}
    Allows the result of arbitrary PHP expressions to be inserted into templates. The result of the expression is output.
    Can be used in CSS files.
    Parameters
    $expression - A valid PHP expression that produces output of some kind
    raw - By default, the result of the expression is HTML-escaped. Setting this parameter to true outputs the raw result. Be careful! This can be a security risk.
     
    {file="$file" extension="[string]"}
    Outputs the URL to a file stored by IPS4's file handling classes.
    Can be used in CSS files.
    Parameters
    $file - Either an instance of the \IPS\File class, or a string representing the stored URL to the file
    extension - The file storage extension used to originally store the file, e.g. calendar_Events. If none is specified, core_Attachment is assumed.
     
    {filesize="$sizeInBytes" decimal="[boolean]"}
    Formats the specified filesize and outputs an appropriate human-readable form.
    Parameters
    $sizeInBytes - An integer representing a file size, in bytes, to be formatted
    decimal - Whether the filesize should be treated as a KB (i.e. 1kb = 1024 bytes) or 1 = 1000. All values are always rounded to one decimal place.
     
    {insert="$filename"}
    Includes a PHP script file
    Parameters
    $filename - The filename of the PHP file to include. The output of the file is buffered and output.
     
    {lang="$languageKey" sprintf="[string]" htmlsprintf="[string]" pluralize="[string]" wordbreak="[boolean]" ucfirst="[boolean]"}
    Inserts a phrase from the language system in the user's chosen language.
    Paramaters
    $languageKey - The key of the language phrase to insert
    sprintf - Comma-separated list of values to replace in the language string. These values are HTML-escaped.
    htmlsprintf - Comma-separated list of values to replace in the language string. These values are not escaped. Be careful!
    pluralize - Comma-separated list of values to pass into any pluralize statements in the language string.
    wordbreak - If true, adds <wbr> tags to the returned string to help prevent strings that break the page width.
    ucfirst - Determines whether the first character of the string should be made uppercase.
     
    {member="$propertyToDisplay" id="[integer]" group="[boolean]" raw="[boolean]"}
    Outputs the property or result of a method called on the member object.
    Parameters
    $propertyToDisplay - One of the properties or methods available on the member object. For example: link() or name.
    id - Member ID to load and display. If not specified, the current member is used.
    group - If true, this tag works on the member's group instead (and so the $propertyToDisplay should be one of the group properties or methods instead)
    raw - By default, the returned output is HTML escaped. Setting this to true means the output won't be escaped. Be careful!
     
    {number="$number"}
    Formats a number according to the user's locale (e.g. with commas or periods)
    Parameters
    $number - Number to format
     
    {prefix="$CSSPropertyName" value="[string]"}
    Shortcut tag which automatically prefixes the provided CSS property with vendor prefixes.
    Can be used in CSS files.
    Parameters
    $CSSPropertyName - The property name to prefix. The supported properties are: transition, transform, animation, animation-name, animation-duration, animation-fill-mode, animation-timing-function, user-select, box-sizing, background-size.
    value - the value of the CSS property.
     
    {request="$requestParameter" raw="[boolean]"}
    Inserts the value of a request parameter.
    Paramaters
    $requestParameter - The parameter from the request object to be inserted.
    raw - By default, the returned value is HTML-escaped. If this parameter is true, the output won't be HTML-escaped. Be careful!
     
    {resource="$path" app="[string]" location="[string]" noprotocol="[boolean]"}
    Returns the absolute URL to the specified resource.
    Can be used in CSS files.
    Parameters
    $path - Relative path to the required resource (path is relative to the current theme's /resource directory)
    app - The app to which the resource belongs.
    location - The location (front/admin/global)
    noprotocol - Whether to make the resulting URL protocol-less (i.e. do not include http:// or https:// at the beginning, which can be useful for resources which are not allowed to be loaded over http on an https connection)
     
    {setting="$settingKey" escape="[boolean]"}
    Inserts the value of a system setting.
    Can be used in CSS files.
    Parameters
    $settingKey - Key of the system setting to insert.
    escape - By default, the raw value is output. If you need the value to be HTML-escaped, pass true for this parameter.
     
    {url="$url" csrf="[bool]" base="[string]" seoTemplate="[string]" seoTitle="[string]" seoTitles="[array]" protocol="[\IPS\Http\Url::PROTOCOL_AUTOMATIC|\IPS\Http\Url::PROTOCOL_HTTPS|\IPS\Http\Url::PROTOCOL_HTTP|\IPS\Http\Url::PROTOCOL_RELATIVE]" fragment="[string]" ref="[string]" plain="[bool]" ips="[string]" noprotocol="[bool]"}
    Generates an \IPS\Http\Url instance of a URL.
    Can be used in CSS files.
    Parameters
    csrf - Adds the CSRF Key to the query string
    base - The base to use, if this is an internal URL.
    seoTemplate - The SEO template for this URL to construct a friendly URL.
    seoTitle - The title to use for the friendly URL.
    seoTitles - An array of friendly URL titles. Not used if seoTitle is used.
    protocol - One of the \IPS\Http\Url::PROTOCOL_* constants to define the protocol to use.
    fragment - Adds a fragment to the end of the URL.
    ref - Sets a base64 encoded referring URL as a query string to the URL (used in conjunction with \IPS\Request::i()->referrer()).
    plain - To output the string value of the URL raw. If omitted, the string value is run through htmlspecialchars().
    ips - If this is an internal IPS URL to the documentation. Ignores all other parameters.
    noprotocol - Makes the URL protocol relative regardless of the defined protocol. This is deprecated, and \IPS\Http\Url::PROTOCOL_RELATIVE should be used instead.
  16. Like
    Rikki got a reaction from shyest for a guide, Pages   
    The foundation of Pages (the application) is the page (the thing).
                            Tip To alleviate confusion in these tutorials, the application "Pages" will always be referred to with a capital letter; pages within the application or community will be lowercase.
    What is a page?
    A page is a container for content. Depending on your needs, a page can simply contain simple content (whether that's plain text, or rich content with images, embeds, and the other things you're used from our other applications), or more complex content like blocks and databases (see later steps to find out more about those).
    If you are comfortable with code, you can also use all of our standard template logic in a page, allowing for some highly custom results. For those who aren't comfortable with coding, there's an easy page builder, allowing you to drag and drop components into your page.
    A page has a URL, and can be automatically added to your menu navigation when you create it, if you wish.
    A page can also have custom permissions, allowing you to restrict who can or cannot access the page. This is great if you want to build special sections of your site, perhaps for staff or premium members only.
    Prior to Invision Community 4.3, Pages were not searchable (although external search engines such as Google will index them). However, if you have a database on a page, the content of the database will be searchable.
    Creating Pages
    Pages are created via the AdminCP, by navigating to Pages -> Pages. A directory listing of your current pages will be shown. Folders are supported here as you'd expect; the URL of the page will reflect this structure. For example, a page called index in a folder called guides will have the URL <your community URL>/guides/index. 
    When you click the Add Page button, you are asked whether you want to use the Page Builder or Manual HTML.

    Page Type
    Page Builder
    After creating the page in the AdminCP, you'll be able to go to the front-end to add content to your page, using drag and drop from the sidebar manager. This option is best for those not familiar with HTML. Manual HTML
    When you choose this option, you'll be provided with a code editor to create your page. Within this code editor you're free to use HTML, as well as the full range of template logic supported by IPS4. With this method, you insert other items (blocks, databases etc.) into the page by using special tags. A sidebar on the editor show you the available tags.  
    Managing content in pages with the drag and drop editor
    If you've created a page using the Page Builder options, after saving the configuration in the AdminCP, you can head over to the page on the front-end to manage its content (click the View Page option from the menu on the page listing screen to easily navigate to it). 
    By default, the page will be empty. Click the sidebar toggle to open the sidebar and see the available widgets. All of the usual widgets are available to you from across the suite, but under the Pages category are a handful of special reusable widgets:

    Block Manager
    Of these, WYSIWYG Editor is the one you'd be most likely to use when setting up your pages. It gives you a standard IPS4 rich text editor to add content to the page. Simply drag it into a location on your page, then click the Edit button to access the editor. We won't cover the other blocks here since they are specific to other kinds of functionality within Pages.
    Managing content in pages using Manual HTML
    When you create a page using manual HTML, you can choose how much of the standard IPS4 wrapper you start with. By default, the suite wrapper is included in the output. This encompasses the header, menu navigation etc., meaning the content of your page is inserted inside this wrapper. With this option disabled, the suite wrapper isn't used - you'll be responsible for providing this (you can however choose a custom page wrapper you've created).
    If you use the suite wrapper, you can also choose whether the standard sidebar is included in the output. The content you enter into the code editor forms the main page content, and the sidebar will be managed as usual with drag and drop on the front-end.
    Adding to Navigation
    When you create a page, you can easily add it to your site's main navigation menu under the Menu tab on the page edit screen. Alternatively, you can add it to the menu manually via the normal menu management process.
     
    Setting as Default
    Often you will wish to set the pages application as your default application, so that you can show a page you created as your default homepage. For this, along with how to create a basic homepage, please refer to the following guide.
      Blocks
  17. Like
    Rikki got a reaction from zbahadir for a guide, ips.ui.dialog   
    Description
    The dialog widget displays popup windows within the page, typically loading content from a remote source.
     
    Usage
    A dialog is defined simply by including the widget key as an attribute on a trigger element. It is recommended that the trigger element be a link or button, so that if the user has javascript disabled their browser can take them to a full-page version of the dialog contents.
    <a href='...' data-ipsDialog data-ipsDialog-url='...'>Launch dialog</a> Dialogs offer special functionality for forms contained with the dialog, enabling them to be automatically validated and submitted via AJAX when used with the form helper from the IPS4 PHP framework. See the remoteVerify and remoteSubmit options below.
     
    Obtaining a dialog reference
    If you need to control a dialog programmatically, you can do so by first obtaining the reference to the dialog. To do so, call the getObj method, passing in the element on which the dialog was created as the parameter:
    // HTML <div id='elementWithDialog' data-ipsDialog> ... </div> // Javascript var dialog = ips.ui.dialog.getObj( $('#elementWithDialog') ); The returned reference to the dialog instance can be used to call the methods shown below.
     
    Creating a dialog programmatically
    Dialogs can be created programmatically by controllers instead of being created on particular elements. To achieve this, call the create method:
    var dialog = ips.ui.dialog.create( object options ); The options parameter should be an object containing keys for the options below.
    This method returns a reference to the dialog instance on which you can call methods to control the dialog, for example:
    dialog.show(); dialog.hide();  
    Instance methods
    show( boolean initOnly )
    Initializes and shows the dialog. If initOnly is true, the dialog is initialized but not immediately shown.
     
    hide()
    Hides the dialog.
     
    remove( boolean hideFirst )
    Removes the dialog from the DOM. If hideFirst is true, the dialog will call hide() and remove itself after the animation is completed.
     
    setLoading( boolean loading )
    If loading is true, indicates to the user that something is being loaded (i.e. shows a spinner in the dialog). If loading is false, removes the loading state. Note: this method doesn't empty the dialog content first. Call instance.updateContent('') manually if desired.
     
    updateContent( string newContent )
    Updates the contents of the dialog with the provided newContent. New controllers/widgets are automatically initialized after updating.
     
    Options
    url
    (String; optional)
    If provided, the dialog contents will be loaded by calling this URL when the dialog is launched.
     
    content
    (Selector; optional)
    If the dialog content already exists in the DOM, this option should be a selector that will locate the wrapper element for the content.
     
    modal
    (Boolean; optional; default true)
    If true, the page background will fade, preventing the user from interacting with it until the dialog is dismissed.
     
    title
    (String; optional)
    Sets the title shown in the dialog window. If not set, no title bar will display.
     
    size
    (String; optional)
    If provided, will set a special class on the dialog designed to change its size. Currently, narrow, medium, wide and fullscreen are supported as values for this option. If not provided, the default dialog width will be used (defined in CSS).
     
    close
    (Boolean; optional; default true)
    Determines whether the dialog should be built with a close button.
     
    fixed
    (Boolean; optional; default false)
    Determines whether the dialog is fixed. A fixed dialog is anchored to the viewport, not the page. Its height will also be fixed, with the content scrolling inside if necessary. If this is false, the dialog will scroll with the page, and it will expand to fit all the content being shown, regardless of length.
     
    remoteVerify
    (Boolean; optional; default true)
    When the dialog contains a form built using the IPS4 PHP framework form helper, this option instructs the dialog to automatically validate the form values and present any errors to the user.
     
    remoteSubmit
    (Boolean; optional; default false)
    When the dialog contains a form built using the IPS4 PHP framework form helper, this option instructs the dialog to submit the form values via AJAX. If remoteVerify is also true, two separate AJAX requests are fired; first, the form is validated, and if successful the form is submitted with a second request.
    If remoteSubmit is true, after a successful submit the dialog is closed automatically. If the flashMessage option is provided, it will be shown at this point.
    By default, remoteSubmit is false, which means forms submit via a traditional page reload.
     
    callback
    (Function; optional)
    Specifies a callback function that will be executed after the dialog has loaded remote content. Note: this option cannot be provided via the data API, and is therefore only available when interacting with ips.ui.dialog directly.
     
    forceReload
    (Boolean; optional; default false)
    By default, once a dialog has loaded its content, it will not do so again even if the dialog is relaunched. By setting this option to true, the dialog will call the url every time it is opened. This option only takes effect when the url option is used.
     
    Events emitted by ips.ui.dialog
    openDialog
    Triggered when the dialog is shown.
    Event data:
    elemID
    ID of the element that triggered the dialog dialogID
    ID of the dialog element dialog
    Reference to the dialog element contentLoaded
    Boolean indicating whether the dialog content has been loaded (may be false if remote content is used)  
    hideDialog
    Triggered when the dialog is hidden.
    Event data:
    elemID
    ID of the element that triggered the dialog dialogID
    ID of the dialog element dialog
    Reference to the dialog element  
    dialogContentLoaded
    Triggered after remote content has been loaded and inserted into the dialog.
    Event data:
    elemID
    ID of the element that triggered the dialog dialogID
    ID of the dialog element dialog
    Reference to the dialog element contentLoaded
    Boolean indicating whether the dialog content has been loaded (always true here)  
    Events to which ips.ui.dialog responds
    closeDialog
    Instructs the dialog to close.
    Event data:
    dialogID (required)
    The ID of the dialog to close (the event is ignored if the ID does not match the current dialog)
     
  18. Like
    Rikki got a reaction from Ali Majrashi for a guide, Adding custom editor buttons   
    If an existing CKEditor plugin isn't available that meets your needs, another alternative that may be suitable is to create a custom button.
     
    What can custom buttons do?
    Custom buttons allow you to create blocks of HTML that are inserted by clicking a button on the editor toolbar. The blocks you create can accept content that users can enter.
    Custom buttons don't have the capabilities of a full CKEditor plugin - they can't be dynamic or use Javascript, for example. But for formatting text the user enters, a custom button may be the best choice.
    Note: although custom buttons tend to be simple, we recommend you have knowledge of HTML, or seek assistance from our peer-to-peer forums.
     
    Creating a custom button
    To create a custom button, navigate to Customization -> Editor -> Toolbars. Click the Add Button button in the header, and then the Custom tab. The form you see has the following fields:
    Button title
    The title seen by users when they hover over the button in the editor Icon
    A small image file that will act at the button icon on the editor. For retina support, upload an icon twice as big as you'd like it to display; it will be resized down by the browser and therefore show high-res. Type
    Three types of content are supported, and they roughly mimic the three types of element display in HTML: Inline - used when the inserted HTML exists somewhere in a line of text. Does not create a new line for the content. Single line block - designed for single lines (e.g. headers), and puts the block on a new line Block - used for multiple lines, and puts the block on a new line Use option
    A custom button can optionally accept a value from the user (aside from what they can type as normal inside the block itself). This option will appear as a popup dialog when the user clicks the button in the editor, and the value they enter is passed into the block when it is rendered. With this field enabled, you'll see an additional setting: Option label
    The text shown to the user requesting a value for the option. HTML
    The actual HTML the button will render in the editor when used. Generally, any HTML is supported but it must be valid. Within this HTML, a couple of special tags can be used: {option}
    If the option is used, this tag is replaced with the value the user entered, as-is. {content}
    If your button will allow the user to type within the generated HTML, insert this tag where the user should be able to type. Click the Save button to create the button. Your icon will be shown on the Buttons Not On Editor toolbar, and from here you can drag it to your live toolbars and configure it as normal.
     
    Using custom styles
    We don't recommend using inline styles in your HTML, because it will be almost impossible for you to update later (posts are built at save-time, not display-time, so if you update a custom button, old posts won't reflect those changes).
    Instead, we suggest using classnames, and adding styles for those classnames in your custom.css theme file. This way, you can update the styles later, and old posts will also reflect the changes.
     
    An example
    Within this documentation we have tip boxes like this:
    Tip This is a tip
    This is a custom editor button we've created that is available to staff. Here's the configuration we used to create this button:
    Button title
    Tip Icon
    Type
    Block Use option
    No HTML <div class='docsBox docsBox_tip'> <div class='docsBox_header'>Tip</div> <div class='docsBox_body'> <div class='ipsType_richText ipsType_break ipsContained'> {content} </div> </div> </div>  
    We then add these styles to our custom.css CSS file:
    .docsBox_header { padding: 5px 10px; color: #fff; font-weight: 500; font-size: 15px; } .docsBox_body { padding: 10px; font-size: 13px; line-height: 1.4; } .docsBox_tip .docsBox_header { background: #2E7D32; } .docsBox_tip .docsBox_body { background: #E8F5E9; } .docsBox_tip .docsBox_body .ipsType_richText { color: #1B5E20; }  
  19. Like
    Rikki got a reaction from Ahmad E. for a guide, Code standards   
    Global scope & closure wrapping
    Variables must not be leaked into the global scope unless there is an explicit functional need for global access. Within function scope, variables must be declared with the var statement.
    To help prevent scope leaking, each script file should be entirely wrapped in an anonymous, self-executing closure, passing the jQuery and Underscore objects as parameters:
    ;( function($, _, undefined){ // Code goes here }(jQuery, _)); This prevents variables from leaking into the global scope, and also ensures jQuery code making use of the dollar variable $ does not conflict with any other code that might be running on the page.
    Note that a semi-colon appears as the first character. This helps prevent errors caused by incorrect semi-colon insertion in previous code, should this script be concatenated with others. It is a defensive coding practice, and recommended in all files.
    Strict mode
    The use of strict mode is required for all default javascript in IPS4. Strict mode helps prevent leaking into the global scope, catches code problems that would otherwise fail silently, and enables javascript engines to perform more optimizations. However, it is important that this is applied using the per-function syntax and not the per-script syntax, otherwise unexpected behavior can occur when script files are concatenated with 3rd-party scripts.
    Given that all script files should be wrapped in a self-executing closure, the syntax for enabling strict mode looks like this:
    ;( function($, _, undefined){ "use strict"; // Script here, e.g. module definition etc. }(jQuery, _)); By putting the "use strict"; statement inside the the closure, we ensure all of our code runs in strict mode without affecting any external code by accident. Note that the strict mode statement must be the very first line of the function, as shown.
    Further information about strict mode and the code requirements it imposes is available at MDN.
    Documentation & commenting
    The use of JSDoc is highly encouraged to document code. Refer to the JSDoc documentation for exact syntax.
    Within scripts, comment blocks /* */ should be reserved for formal documentation and situations where large blocks of existing code need to be commented out temporarily. Line-by-line comments should always use the single-line // comment style.
    /** * Formal documentation */ // Informal comments to describe code Semi-colons
    Semi-colons must be used at the end of every statement, even when function/object literals are being assigned. For example:
    // Simple statements $('#element').doSomething(); var test = 'value'; return 'text'; // Function and object literals var test = function () { ... }; var test2 = { key1: 'value' }; Names
    All names (variables, methods, properties etc.) should use lowerCamelCase, such as deselectAll, createModule and itemSelector.
    Logging
    You should not use console.log for debugging. This does not provide for disabling debugging in production, and can break pages on older browsers if not accounted for. A debugging method is provided via Debug.log that addresses these concerns, and should be used instead.
    Line length
    Aim to keep the line length below 120 characters to maintain readability. Longer lines should be split immediately after a comma or operator, with the remainder of the statement indented further to ensure clarity. For example:
    if( ( options.dataSource && options.dataSource.indexOf('#') === 0 && $( options.dataSource ).length ) || originalTextField.is('[list]') ){ jQuery chaining
    It is recommended that multiple jQuery methods chained on an element are placed on newlines to improve clarity. Additionally, indentation should be used to reflect the current working level of the chain. For example:
    $('selector') .find('.classname') .hide() .end() .find('.otherClassname') .css('width', '100%') .show() .end() .append( $('<div/>').attr( { id: 'someID' }); By indenting in this way, we make it clear that the hide() method applies only to the elements matching .classname, before calling end() to return to the original working level - and so on.
  20. Like
    Rikki got a reaction from SlimTall for a guide, Pages   
    The foundation of Pages (the application) is the page (the thing).
                            Tip To alleviate confusion in these tutorials, the application "Pages" will always be referred to with a capital letter; pages within the application or community will be lowercase.
    What is a page?
    A page is a container for content. Depending on your needs, a page can simply contain simple content (whether that's plain text, or rich content with images, embeds, and the other things you're used from our other applications), or more complex content like blocks and databases (see later steps to find out more about those).
    If you are comfortable with code, you can also use all of our standard template logic in a page, allowing for some highly custom results. For those who aren't comfortable with coding, there's an easy page builder, allowing you to drag and drop components into your page.
    A page has a URL, and can be automatically added to your menu navigation when you create it, if you wish.
    A page can also have custom permissions, allowing you to restrict who can or cannot access the page. This is great if you want to build special sections of your site, perhaps for staff or premium members only.
    Prior to Invision Community 4.3, Pages were not searchable (although external search engines such as Google will index them). However, if you have a database on a page, the content of the database will be searchable.
    Creating Pages
    Pages are created via the AdminCP, by navigating to Pages -> Pages. A directory listing of your current pages will be shown. Folders are supported here as you'd expect; the URL of the page will reflect this structure. For example, a page called index in a folder called guides will have the URL <your community URL>/guides/index. 
    When you click the Add Page button, you are asked whether you want to use the Page Builder or Manual HTML.

    Page Type
    Page Builder
    After creating the page in the AdminCP, you'll be able to go to the front-end to add content to your page, using drag and drop from the sidebar manager. This option is best for those not familiar with HTML. Manual HTML
    When you choose this option, you'll be provided with a code editor to create your page. Within this code editor you're free to use HTML, as well as the full range of template logic supported by IPS4. With this method, you insert other items (blocks, databases etc.) into the page by using special tags. A sidebar on the editor show you the available tags.  
    Managing content in pages with the drag and drop editor
    If you've created a page using the Page Builder options, after saving the configuration in the AdminCP, you can head over to the page on the front-end to manage its content (click the View Page option from the menu on the page listing screen to easily navigate to it). 
    By default, the page will be empty. Click the sidebar toggle to open the sidebar and see the available widgets. All of the usual widgets are available to you from across the suite, but under the Pages category are a handful of special reusable widgets:

    Block Manager
    Of these, WYSIWYG Editor is the one you'd be most likely to use when setting up your pages. It gives you a standard IPS4 rich text editor to add content to the page. Simply drag it into a location on your page, then click the Edit button to access the editor. We won't cover the other blocks here since they are specific to other kinds of functionality within Pages.
    Managing content in pages using Manual HTML
    When you create a page using manual HTML, you can choose how much of the standard IPS4 wrapper you start with. By default, the suite wrapper is included in the output. This encompasses the header, menu navigation etc., meaning the content of your page is inserted inside this wrapper. With this option disabled, the suite wrapper isn't used - you'll be responsible for providing this (you can however choose a custom page wrapper you've created).
    If you use the suite wrapper, you can also choose whether the standard sidebar is included in the output. The content you enter into the code editor forms the main page content, and the sidebar will be managed as usual with drag and drop on the front-end.
    Adding to Navigation
    When you create a page, you can easily add it to your site's main navigation menu under the Menu tab on the page edit screen. Alternatively, you can add it to the menu manually via the normal menu management process.
     
    Setting as Default
    Often you will wish to set the pages application as your default application, so that you can show a page you created as your default homepage. For this, along with how to create a basic homepage, please refer to the following guide.
      Blocks
  21. Like
    Rikki got a reaction from evelynt@madscience.org for a guide, Targeting elements on specific pages with CSS   
    Occasionally, you'll want to be able to change the style of a particular element on a particular page, without affecting similar elements on other pages. For example, lets say you wanted to change how the .ipsPageHeader element looks in topic view, to make the title bigger, but without changing it for all other pages that also use .ipsPageHeader.
     
    Adding a classname - the wrong way
    One method would be to edit the template for topic view, add a classname to the element, and then create a style using that new classname as the selector. This works, but it has a drawback - because you've edited the template, IPS4 won't be able to automatically update it for you when you upgrade to newer versions of the IPS Community Suite. We always suggest you try and avoid editing templates directly, for this reason.
     
    Using page-specific selectors - the right way
    There's a better way - every page in IPS4 includes some special attributes on the body tag that identify the app, module and controller being viewed. You can use these to write a CSS selector to only target pages that match the ones you want. Going back to our example, we could target .ipsPageHeader in topic view like so:
    body[data-pageapp="forums"][data-pagemodule="forums"][data-pagecontroller="topic"] .ipsPageHeader { ...your styles } This works because topic view is generated by the topic controller, in the forums module, in the forums app. All pages in the IPS Community Suite follow this controller/module/application structure.
    You can mix and match these. If you want to style all page headers in the forums app only, you could simplify the above to:
    body[data-pageapp="forums"] .ipsPageHeader { ...your styles } You can find out the right values to use by going to the page you want to target, viewing the source in a tool like Web Inspector, and finding the body tag - look for the special data-page* attributes that are used for that page.
    By including these styles in your custom.css file in your theme, you can target specific elements on specific pages, without making it difficult to upgrade your community later.
  22. Like
    Rikki got a reaction from Meddysong for a guide, Pages   
    The foundation of Pages (the application) is the page (the thing).
                            Tip To alleviate confusion in these tutorials, the application "Pages" will always be referred to with a capital letter; pages within the application or community will be lowercase.
    What is a page?
    A page is a container for content. Depending on your needs, a page can simply contain simple content (whether that's plain text, or rich content with images, embeds, and the other things you're used from our other applications), or more complex content like blocks and databases (see later steps to find out more about those).
    If you are comfortable with code, you can also use all of our standard template logic in a page, allowing for some highly custom results. For those who aren't comfortable with coding, there's an easy page builder, allowing you to drag and drop components into your page.
    A page has a URL, and can be automatically added to your menu navigation when you create it, if you wish.
    A page can also have custom permissions, allowing you to restrict who can or cannot access the page. This is great if you want to build special sections of your site, perhaps for staff or premium members only.
    Prior to Invision Community 4.3, Pages were not searchable (although external search engines such as Google will index them). However, if you have a database on a page, the content of the database will be searchable.
    Creating Pages
    Pages are created via the AdminCP, by navigating to Pages -> Pages. A directory listing of your current pages will be shown. Folders are supported here as you'd expect; the URL of the page will reflect this structure. For example, a page called index in a folder called guides will have the URL <your community URL>/guides/index. 
    When you click the Add Page button, you are asked whether you want to use the Page Builder or Manual HTML.

    Page Type
    Page Builder
    After creating the page in the AdminCP, you'll be able to go to the front-end to add content to your page, using drag and drop from the sidebar manager. This option is best for those not familiar with HTML. Manual HTML
    When you choose this option, you'll be provided with a code editor to create your page. Within this code editor you're free to use HTML, as well as the full range of template logic supported by IPS4. With this method, you insert other items (blocks, databases etc.) into the page by using special tags. A sidebar on the editor show you the available tags.  
    Managing content in pages with the drag and drop editor
    If you've created a page using the Page Builder options, after saving the configuration in the AdminCP, you can head over to the page on the front-end to manage its content (click the View Page option from the menu on the page listing screen to easily navigate to it). 
    By default, the page will be empty. Click the sidebar toggle to open the sidebar and see the available widgets. All of the usual widgets are available to you from across the suite, but under the Pages category are a handful of special reusable widgets:

    Block Manager
    Of these, WYSIWYG Editor is the one you'd be most likely to use when setting up your pages. It gives you a standard IPS4 rich text editor to add content to the page. Simply drag it into a location on your page, then click the Edit button to access the editor. We won't cover the other blocks here since they are specific to other kinds of functionality within Pages.
    Managing content in pages using Manual HTML
    When you create a page using manual HTML, you can choose how much of the standard IPS4 wrapper you start with. By default, the suite wrapper is included in the output. This encompasses the header, menu navigation etc., meaning the content of your page is inserted inside this wrapper. With this option disabled, the suite wrapper isn't used - you'll be responsible for providing this (you can however choose a custom page wrapper you've created).
    If you use the suite wrapper, you can also choose whether the standard sidebar is included in the output. The content you enter into the code editor forms the main page content, and the sidebar will be managed as usual with drag and drop on the front-end.
    Adding to Navigation
    When you create a page, you can easily add it to your site's main navigation menu under the Menu tab on the page edit screen. Alternatively, you can add it to the menu manually via the normal menu management process.
     
    Setting as Default
    Often you will wish to set the pages application as your default application, so that you can show a page you created as your default homepage. For this, along with how to create a basic homepage, please refer to the following guide.
      Blocks
  23. Like
    Rikki got a reaction from ANDROS89 for a guide, Variables   
    Each template bit can have variables passed into it by the backed PHP code, and these variables can be used by the template bit to control the display. Consult either the template editor or designer's mode guides (depending on your preference) to find out how to determine which variables are available to a template.
    As well as these local variables, you can access the various objects created by the IPS4 PHP framework.
     
    Variables are escaped
    It's important to note that by default, all variable values are HTML-escaped when you output them in templates. This is for security, and ensures you don't inadvertently output some malicious HTML that is then processed by the browser and displayed. If a variable $value contained:
    <strong>Example</strong> Then outputting it in a template like so:
    Here's the variable value: {$value} Would actually send:
    Here's the variable value: &lt;strong&gt;Example&lt;/strong&gt; This is safe for the browser to display.
    Bypassing this protection
    Of course, in some situations, you want the raw HTML to be output, and not escaped. To do so, you can use the raw modifier on the variable:
    Here's the variable value: {$value|raw} Warning Using this modifier on untrusted content is a security risk. You should not output raw user-supplied HTML unless it has been properly sanitized and you are certain it is safe. Content that comes from IPS4's rich text editor is safe to output with this modifier.
     
  24. Like
    Rikki got a reaction from BomAle for a guide, UI widgets   
    What's a widget?
    UI widgets are modules that:
    Are instantiated on individual DOM nodes Provide some kind of UI functionality Benefit from being reusable Come with an automatic data API functionality A UI widget is created as a standard module, under the ips.ui namespace.
    Basic widget boilerplate
    ;( function($, _, undefined){ "use strict"; ips.createModule('ips.ui.widgetName', function(){ var respond = function (elem, options, e) { }; // Register this module as a widget to enable the data API ips.ui.registerWidget( 'widgetName', ips.ui.widgetName ); return { respond: respond }; }); }(jQuery, _)); In the example above, a module is created with the module path ips.ui.widgetName. UI widget modules must expose a response method, either the default respond method or by manually specifying a method when the widget is registered (see below). This is the method that is called when the widget is instantiated.
    Registering a UI widget
    A module is registered as a widget by calling the ips.ui.registerWidget method before the module returns its public methods object.
    ips.ui.registerWidget( string widgetKey, object handlerModule [, array acceptedOptions] [, object widgetOptions] [, function callback] ); The method takes the following parameters:
    widgetKey (required)
    The key that is used to reference this widget throughout the software. The key is prefixed with ips when used, to prevent naming collisions. The key forms both the data API attribute key, and the name of the jQuery plugin that can be used to instantiate the widget. Assuming the widget key is set to widget, the data API attribute key and jQuery plugin would be: data-ipsWidget // Data API attribute $('element').ipsWidget(); // jQuery plugin method  
    handlerModule (required)
    A reference to the module that will respond when the widget is instantiated. In practice, this should be a self reference to the module that is being defined.
    acceptedOptions (optional)
    An array of strings defining the options that this widget will accept. When the widget is instantiated, if these options are defined their values will be passed back to the respond method.
    widgetOptions (optional)
    An object containing options for how this widget will be registered or instantiated. The available options are:
    lazyLoad
    By default, widgets are instantiated as soon as they are seen in the DOM. By setting this option to true the widget is not instantiated until the user interacts with the element.
    lazyEvent
    If the lazyLoad option is enabled, this option defines the event that will be watched for. When the event name set here is triggered, the widget will be initialized.
    makejQueryPlugin
    By default, widgets will have an associated jQuery plugin created to allow them to be instantiated programatically. This functionality can be disabled by setting this option to false.
    callback (optional)
    A widget must have a response method, which is called when it is initialized on an element. By default, a method with the name respond is looked for, but a different response function can be set by passing it as this parameter.
    Events
    The javascript framework in IPS4 relies heavily on events. Controllers in particular are completely decoupled and cannot directly communicate with one another. Instead, communication happens by triggering and receiving events.
    It is therefore important that your widget emits events when key actions happen. This allows controllers, other UI widgets, even third-party scripts to respond when something happens within your widget. As an example, the ips.ui.menu widget emits a number of events, including menuOpened, menuClosed and menuItemSelected. Each of these events also provides a number of data items relevant to the event, which can be used by event handlers listening for those events.
    It is this event interaction that facilitates dynamic pages within the IPS Community Suite, so it's important your widget also emits relevant events.
    When you emit an event, it is usually most appropriate to emit it on the element the widget is registered on. Emitting an event uses the standard jQuery syntax:
    $( elem ).trigger( 'myWidgetEvent', { color: 'red', size: 'large' } ); Widget initialization
    A widget is initialized either as soon as it is seen in the DOM, or, if the lazyLoad option is enabled, when the user interacts with the element the widget is created on. In both cases, the initialization process is the same. The internal widget manager will call the response method for the widget (respond by default, or whatever function is passed as the callback option), passing in the following parameters:
    function respond( element elem, array options, event ev ) elem
    A reference to the element on which the widget has been initialized options
    An array of options that have been specified on the element, and which were in the list of expected options when the widget was first registered. Any other options are ignored and won't be passed through. ev
    If the widget is initialized in response to a user interaction because lazyLoad is enabled, this parameter will contain the original event object. It will be undefined if the widget is being initialized on load. Example widget
    Let's take a trivial example, and assume we're creating a widget which hides an element:
    ;( function($, _, undefined){ "use strict"; ips.createModule('ips.ui.hideElem', function(){ var respond = function (elem, options, e) { if( options.animate ){ $( elem ).fadeOut(); } else { $( elem ).hide(); } $( elem ).trigger( 'hiddenElement' ); }; ips.ui.registerWidget( 'hideElem', ips.ui.hideElem, [ 'animate' ], { lazyLoad: true, lazyEvent: 'click' } ); return { respond: respond }; }); }(jQuery, _)); When we register the widget, we set up an animate option in the acceptedOptions parameter. In the widgetOptions parameter, we set lazyLoad to true, and the lazyEvent to click - meaning our widget won't be initialized until the user clicks on the element.
    In our respond method, we simply check if options.animate is true, fading out if so and hiding if not.
    This example widget could be initialized on an element like so:
    <button data-ipsHideElem data-ipsHideElem-animate='true'>Click to hide me</button>  
  25. Like
    Rikki got a reaction from tbar for a guide, Introduction to the CSS framework   
    Introduction
    In order to properly differentiate between CSS classes and HTML elements that form part of the IPS4 framework and those that do not, and in order to create a logical structure that can be understood at a glance, naming conventions are applied as follows.
    Framework classes & elements
    The IPS4 CSS framework is split into loosely-defined 'modules'. A module groups together related styles in a single file, with the aim of making it clearer which styles will be applied to a given element, and also to make it easier to find those styles to edit in the CSS files.
    All framework classes and elements take the name format ipsModule, where Module is the type of style being defined. Within a module, additional classes can be defined in the format ipsModule_option. Note that the module name and module options both use lowerCamelCase notation, with the module name and option separated by an underscore.
    Normally, an element will receive the base module class, plus some options. There are some cases where only the option class is needed; see individual module documentation for details.
    In general, the framework shouldn't be used with element IDs, since this restricts their use to one per page. The exception to this is aspects of the layout module, where page structure will naturally only exist once.
    Example of framework names:
    .ipsMenu .ipsTabs_item #ipsLayout_mainArea .ipsComment_hasChildren  
    Writing CSS for custom themes
    As a rule, you shouldn't edit the framework CSS files directly. Doing so is prone to breaking future updates, or at least making it harder to upgrade your site between versions.
    Instead, all of your changes should live in the custom.css file at /core/front/custom/. You can create other CSS files within the custom directory if you wish and these will also be included. CSS files in the custom directory are not modified by the IPS4 upgrader, meaning your changes will safely persist across versions.
    Determining which elements use which CSS classes
    When editing your theme, we recommend you make use of the developer tools available in your browser to inspect the page and find out which CSS classes are applied to elements. Consult the documentation for your choice of browser to find out how to do this. This is an example of Chrome's Web Inspector:

     
    Writing CSS for custom applications
    CSS for your custom applications belongs in the <app>/dev/css/front/ directory. Consult the PHP framework documentation for information on using CSS files you create here.
  26. Like
    Rikki got a reaction from Meddysong for a guide, Handling right-to-left languages   
    The IPS Community Suite has built-in support for languages that use right-to-left text (including Arabic, Persian and others), and if you are creating a theme to share with others, you should ensure it is compatible with right-to-left display. Doing so is easy.
     
    RTL-specific CSS
    When RTL display is used, certain CSS properties need to be reversed; for example, if you position something left in LTR languages, when shown in RTL it would need to be positioned right instead.
    The global template in IPS4 always has the dir attribute specifying the text direction (the value is either ltr or rtl), and it is this attribute we can use to add direction-specific styles.
    Let's imagine you have some CSS in your theme like this:
    .yourClass { font-weight: bold; position: absolute; left: 15px; top: 15px; padding-left: 30px; } Some of these styles need to be separated out for RTL or the theme won't look right. So, by using the dir attribute on the html tag, what we instead need to write is:
    /* These styles are the same regardless of text-direction */ .yourClass { font-weight: bold; position: absolute; top: 15px; } /* LTR styles */ html[dir="ltr"] .yourClass { left: 15px; padding-left: 30px; } /* RTL styles */ html[dir="rtl"] .yourClass { right: 15px; padding-right: 30px; } That's it! RTL languages will now correctly position the element on the right-hand side of the screen, while LTR languages will show it on the left as expected.
    Whenever you use styles impacted by text direction, you should split them out in this way.
     
    RTL-specific icons
    The IPS Community Suite makes extensive use of FontAwesome icons. Some of the icons need to be flipped for RTL languages (such as arrows) and if you use the standard classnames (e.g. fa-caret-left), we automatically flip these so that they are correct for RTL languages.
    If you manually specify icons in your CSS classes using the unicode code, you will need to adjust them for RTL so that their opposite icon is used. For example, if you do this in your CSS:
    /* This uses the unicode for FA's 'angle-right' icon */ .nextLink:after { font-family: 'FontAwesome'; content: '\f105'; } You will need to change it to be:
    .nextLink:after { font-family: 'FontAwesome'; } html[dir="ltr"] .nextLink:after { content: '\f105'; } html[dir="rtl"] .nextLink:after { content: '\f104'; }  
    Consider your Javascript
    This usually will not require any action. However, if you have any custom JavaScript which adds user interaction, consider if any changes need to be made. For example, if you have a menu which opens from the left, it may need to open from the right. If you are only using the UI widgets already in the IPS Community Suite, these already make all such considerations so no action will be necessary.
  27. Like
    Rikki got a reaction from LiquidFractal for a guide, Adding custom fields   
    Custom fields are what you use to make a database that is specific to your needs. IPS4 supports a wide range of field types so that you can collect data in the appropriate formats, from text and numbers, to upload fields and YouTube embeds.
    We're going to create a few different fields to gather information about each recipe that we can then display in our database. They are:
    List of ingredients Prep time Cook time Cuisine A link to a YouTube video recipe We don't need fields for the recipe title, or the instructions. Databases already provide a title field, and we'll also use the built-in content field for the recipe instructions.
    We'll see how to set up the custom fields, as well as how to customize their appearance.
     
    Ingredients field
    1. To create a new field, hover on the Pages tab in the AdminCP, and then click the Fields link under the Recipes database in the menu. The screen will show you the default built-in fields for your database, including Title and Content.
    2. Click the Create New button; you'll see a form where you configure your field.
    3. For Title, enter "Ingredients". This is the field title users will see when adding/viewing recipes on your site.
    4. For Description, enter "One per line". The description is only shown on the add/edit record form, so it's a good place to enter special instructions for filling it in.
    5. For the type, we'll choose Editor in this case, because it will allow the user to format the list if they wish. The other fields on the form will change depending on which field type you choose, since each has specific options.
    6. We don't require a maximum length, but we do want to require this field to be completed, so leave these settings at their default values.
    7. On the Display tab, we'll configure how the field content is shown to users. First, enter ingredients as the field key. This key is how IPS4 identifies this field in templates. We won't actually be using it in this tutorial, but it's good practice to set it anyway so you can use it later if needed.
    8. We don't want our list of ingredients to show on the listing screen, so disable that option.
    9. We do, however, want it to show on the record display screen, since this is the main screen for viewing a recipe. A badge isn't ideal for showing content from an Editor, so change the Display View Format to the simple Label: Value option as shown:

    Display View Format
    10. We'll show the list of ingredients above the main record content, so make sure Above the item content is selected for the Display option.
    11. Finally, there's no need to allow this field to be updated when viewing a record; instead, users will go to the full edit form. You can leave the Editable when viewing a record option disabled.
    12. Save the form to create the field.
     
    Other fields
    Other fields
    Other fields are created in the same way, so instead of going through the whole process again, here's the configuration options you need for each field. Where a configuration option isn't listed, leave it at its default value.
    Note: Some field types, including the Select Box type that Cuisine uses (see below), support a fixed set of options from which the user can choose. You'll set these up as key/value pairs in the AdminCP, but the user will only see the values when they select them. The key is just used internally by IPS4 and in custom templates to identify the value, and is best kept as a single lowercase word.
     
    Prep time
    Name: Prep Time
    Type: Text
    Required: No
    Template key: prep-time
    Listing view format: Label: Value
    Display view format: Label: Value
     
    Cook time
    Name: Cook Time
    Type: Text
    Required: No
    Template key: cook-time
    Listing view format: Label: Value
    Display view format: Label: Value
     
    Cuisine
    Name: Cuisine
    Type: Select Box
    Content: (key/value)
    indian / Indian italian / Italian american / American mexican / Mexican Allow filtering: Yes
    Required: Yes
    Template key: cuisine
    Listing view format: Label: Value
    Show to right of listing area: Yes
    Display view format: Label: Value
    Display: Above the item content
     
    Video recipe
    Name: Video tutorial
    Type: YouTube Embed
    Required: No
    Template key: video-tutorial
    Show in listing template: No
    Show in display template: Yes
    In a record, display as: Embedded Player
     
    That's it! If you now head over to the front-end page for your database, click into a category, and click the Add New Recipe button, you'll see your fields on the form, ready to collect information! Feel free to add some sample records to try it out.
    You'll also see the Record Image field that the database provides automatically (discussed earlier). When you upload an image here, you'll see it is automatically included in the record view for you.
    Here's an example recipe in our database:

    Listing View

    Record View
  28. Like
    Rikki got a reaction from LiquidFractal for a guide, Setting up categories   
    The next thing we're going to focus on is creating our categories. If you've created categories in the other IPS4 applications, it's a very similar process.
              How to set up categories
    When you hover on the Pages tab in the AdminCP, you'll see your database is now listed as a menu item, and a link for Categories is available underneath. Click this link to view the current categories. You'll see a default "Records" category.
    Click Create New to add a new one. We'll name this category Main Courses as an example. There's no need to manually enter a manual Friendly URL 'slug' (the slug is the part of the URL that identifies this category, e.g. <yourcommunity>/recipes/main-courses/record) - one will be created automatically based on the category name you enter.

    Category Creation
    We do want to show the record listing for this category, since it'll show recipes. We can leave Star Ratings disabled, and we'll leave Set Custom Permissions disabled too. However, if you were creating a category and wanted to use permissions different to those you set up for the database, you could enable that option and do so here.
    Finally, we'll leave the default database templates selected. If you had a situation where you wanted to use different templates for individual categories, these settings allow you to do so.
    We will ignore the other two tabs on this form for now; we aren't using the functionality they control.
    Refreshing our front-end, you'll now see your new category:

    Category List
     
    You can now go back and either delete the Records category, or edit it and rename it and adjust the settings to match. You can also create other categories, for example:
    Appetizers Desserts Snacks
  29. Like
    Rikki got a reaction from BN_IT_Support for a guide, (Advanced) Building dynamic blocks based on the page being viewed   
    For more advanced sites built with Pages, you may want to change the output of a custom HTML or PHP block depending on which page the user is viewing. For example, if you have a custom menu, you may want to highlight the active item.
    We can implement this in Pages by checking the underlying page URL parameters. Although you access a page with a friendly URL (FURL) like http://<yourcommunity>/section/page, behind the scenes this is mapped to a raw URL, such as http://<yourcommunity>/index.php?app=cms&module=pages&controller=page&path=/section/page. Notice the path parameter allows us to identify which page we're accessing. When we access the \IPS\Request::i() object, we can compare against this parameter, like so:
    {{if strpos( \IPS\Request::i()->path, 'section/page' ) !== FALSE}} <!-- We know the user is on /section/page --> {{elseif strpos( \IPS\Request::i()->path, 'othersection/otherpage' ) !== FALSE}} <!-- We know the user is on /othersection/otherpage --> {{endif}} Note that for reliability, we're using PHP's strpos function to check for the presence of the page URL in the path parameter, rather than a simple comparison.
    Example
    Let's assume we've created a Manual HTML block, we're adding HTML to show a menu, and we want to highlight the correct item based on the page. Here's what our block contents might look like:
    <ul class='ipsList_inline cMyMenu'> <li {{if strpos( \IPS\Request::i()->path, 'help/home' ) !== FALSE}}class='active'{{endif}}> <a href='/help/home'>Home</a> </li> <li {{if strpos( \IPS\Request::i()->path, 'help/faq' ) !== FALSE}}class='active'{{endif}}> <a href='/help/faq'>FAQ</a> </li> <li {{if strpos( \IPS\Request::i()->path, 'help/tutorials' ) !== FALSE}}class='active'{{endif}}> <a href='/help/tutorials'>Tutorials</a> </li> </ul> If we had many items to show, it would get tedious to list them all like this. We could instead do it as a loop:
    // Using a PHP variable to store an array of pages => page names that we'll loop over {{$myPages = array('help/home' => "Home", 'help/faq' => "FAQ", 'help/tutorials' => "Tutorials", 'help/qna/listing' => "Questions", 'help/qna/recent' => "Recent Questions", 'help/contact' => "Contact Us");}} <ul class='ipsList_inline cMyMenu'> {{foreach $myPages as $url => $title}} <li {{if strpos( \IPS\Request::i()->path, $url ) !== FALSE}}class='active'{{endif}}> <a href='{$url}'>{$title}</a> </li> {{endforeach}} </ul> Now to add new items to our custom menu, we just have to add them to the array.
  30. Like
    Rikki got a reaction from BomAle for a guide, Controllers   
    Overview
    Controllers are special modules that handle specific functionality on specific pages. They are not necessarily reusable in different contexts, although some may be. A controller is initialized on an individual element, and that element becomes the controller's scope. A controller responds to user events (such as click) and events triggered by UI widgets or sub-controllers, and manipulates its scope element accordingly.
    The scope of a controllers functionality is entirely flexible. A controller might be initialized on a very small fragment of the page and perform just one task, or it might be initialized on a main wrapper and handle functionality that applies to the whole page. A controller can be initialized on an element even if it's a descendent of another element with a controller; this is a common pattern whereby the child controller can emit events that the parent controller can respond to.
    Generally, keep a controller narrowly focused on one aspect of the page. If a controller ends up handing distinct and unrelated functionality, split it into smaller controllers.
    Creating a controller
    A controller is registered in a slightly different way to standard modules; instead, an object literal is passed to the method ips.controller.register:
    ;( function($, _, undefined){ "use strict"; ips.controller.register('type.controllerID', { initialize: function () { // Controller events are initialized here } }); }(jQuery, _)); A controller, at the very least, must define an initialize method, which is called when the controller is initialized on an element. The initialize method should set up events that are handled by this controller only; if other initialization tasks are necessary, it is recommended that you define a setup method within the controller, and call that at the start or end of the initialize method as appropriate.
    Within the controller definition, this refers to the controller instance. That means controller methods can be called internally with this.someMethod().
    A reference to the element that the controller is initialized on (its scope) is available with the scope property:
    // An example which hides the element this.scope.hide(); Method and property names
    For clarity, it is recommended that event handler method names (i.e. the handlers to events you set up in initialize) are not prefixed with an underscore, while other methods and properties of the controller are. This helps create a clear distinction between core functionality of the controller (the event handlers) and supporting methods.
    Handling events
    Event handling is the core purpose of a controller. There are three special methods available for watching and triggering events. Two are named after their jQuery counterparts, but add controller-specific behavior.
    this.on
    Used for watching and responding to events.
    this.on( [element elem,] string eventType [, selector delegate], function callback ); elem
    A reference to the element on which the event will be watched for. If not specified, this.scope is used by default. eventType
    The event being watched for. This can be a default browser event, like click, or events from widgets and models, like menuItemSelected. delegate
    A delegate selector can optionally be specified. See the jQuery documentation for more information. callback
    A callback function, called when this event is observed. The function specified here is automatically bound to this, so internal methods can be passed simply by referencing them like so: this.on( 'click', this.internalMethod );  
    this.trigger
    Used to emit events that originate from this controller (specifically, the scope element).
    this.trigger( [element elem,] string eventType [, object data] ); elem
    A reference to the element on which the event will be triggered. If not specified, this.scope is used by default. eventType
    The event being triggered. data
    An object containing data relevant to the event.  
    this.triggerOn
    Used to emit events directly on sub-controllers from a parent controller.
    this.triggerOn( string controllerName, string eventType [, object data] ); controllerName
    The controller name to find and trigger the event on. The wildcard character (*) is supported at the end of this parameter and the event will be triggered on all matching controllers. Examples: core.front.core.comment core.front.core.* core.* eventType
    The event being triggered. data
    An object containing data relevant to the event.
  31. Like
    Rikki got a reaction from ipbfuck for a guide, Template plugins   
    It's often useful to transform raw values in some way, and this is achieved in IPS4 with template plugins. Template plugins take a value, and optionally some arguments, and output some transformed value.
    The syntax for template tags is:
    {pluginkey="<value>" argument="..."} The value can be a normal string, or it could be a variable coming from elsewhere.
    Template plugins can always be used in templates, but some can also be used in CSS files. Those that can are identified below.
     
    Available plugins
    {advertisement="$location"}
    The HTML for the specified ad location
    Parameters
    $location - A valid advertisement location
     
    {datetime="$timestamp" dateonly="[boolean]" norelative="[boolean]" lowercase="[boolean]" short="[boolean]"}
    Shows a time formatted according to the user's locale
    Parameters
    $timestamp - A timestamp to transform into a date
    dateonly - Show only the date (with no time)
    norelative - By default, relative times will be used (e.g. 8 hours ago). To always show an absolute date/time, set this to true.
    lowercase - By default, date strings will be capitalized where necessary (e.g. Yesterday, 8:32pm). Setting this to true ensures it is lowercase, for use in a sentence.
    short - Uses a very short date format (ideal for mobile devices)
     
    {expression="$expression" raw="[boolean]"}
    Allows the result of arbitrary PHP expressions to be inserted into templates. The result of the expression is output.
    Can be used in CSS files.
    Parameters
    $expression - A valid PHP expression that produces output of some kind
    raw - By default, the result of the expression is HTML-escaped. Setting this parameter to true outputs the raw result. Be careful! This can be a security risk.
     
    {file="$file" extension="[string]"}
    Outputs the URL to a file stored by IPS4's file handling classes.
    Can be used in CSS files.
    Parameters
    $file - Either an instance of the \IPS\File class, or a string representing the stored URL to the file
    extension - The file storage extension used to originally store the file, e.g. calendar_Events. If none is specified, core_Attachment is assumed.
     
    {filesize="$sizeInBytes" decimal="[boolean]"}
    Formats the specified filesize and outputs an appropriate human-readable form.
    Parameters
    $sizeInBytes - An integer representing a file size, in bytes, to be formatted
    decimal - Whether the filesize should be treated as a KB (i.e. 1kb = 1024 bytes) or 1 = 1000. All values are always rounded to one decimal place.
     
    {insert="$filename"}
    Includes a PHP script file
    Parameters
    $filename - The filename of the PHP file to include. The output of the file is buffered and output.
     
    {lang="$languageKey" sprintf="[string]" htmlsprintf="[string]" pluralize="[string]" wordbreak="[boolean]" ucfirst="[boolean]"}
    Inserts a phrase from the language system in the user's chosen language.
    Paramaters
    $languageKey - The key of the language phrase to insert
    sprintf - Comma-separated list of values to replace in the language string. These values are HTML-escaped.
    htmlsprintf - Comma-separated list of values to replace in the language string. These values are not escaped. Be careful!
    pluralize - Comma-separated list of values to pass into any pluralize statements in the language string.
    wordbreak - If true, adds <wbr> tags to the returned string to help prevent strings that break the page width.
    ucfirst - Determines whether the first character of the string should be made uppercase.
     
    {member="$propertyToDisplay" id="[integer]" group="[boolean]" raw="[boolean]"}
    Outputs the property or result of a method called on the member object.
    Parameters
    $propertyToDisplay - One of the properties or methods available on the member object. For example: link() or name.
    id - Member ID to load and display. If not specified, the current member is used.
    group - If true, this tag works on the member's group instead (and so the $propertyToDisplay should be one of the group properties or methods instead)
    raw - By default, the returned output is HTML escaped. Setting this to true means the output won't be escaped. Be careful!
     
    {number="$number"}
    Formats a number according to the user's locale (e.g. with commas or periods)
    Parameters
    $number - Number to format
     
    {prefix="$CSSPropertyName" value="[string]"}
    Shortcut tag which automatically prefixes the provided CSS property with vendor prefixes.
    Can be used in CSS files.
    Parameters
    $CSSPropertyName - The property name to prefix. The supported properties are: transition, transform, animation, animation-name, animation-duration, animation-fill-mode, animation-timing-function, user-select, box-sizing, background-size.
    value - the value of the CSS property.
     
    {request="$requestParameter" raw="[boolean]"}
    Inserts the value of a request parameter.
    Paramaters
    $requestParameter - The parameter from the request object to be inserted.
    raw - By default, the returned value is HTML-escaped. If this parameter is true, the output won't be HTML-escaped. Be careful!
     
    {resource="$path" app="[string]" location="[string]" noprotocol="[boolean]"}
    Returns the absolute URL to the specified resource.
    Can be used in CSS files.
    Parameters
    $path - Relative path to the required resource (path is relative to the current theme's /resource directory)
    app - The app to which the resource belongs.
    location - The location (front/admin/global)
    noprotocol - Whether to make the resulting URL protocol-less (i.e. do not include http:// or https:// at the beginning, which can be useful for resources which are not allowed to be loaded over http on an https connection)
     
    {setting="$settingKey" escape="[boolean]"}
    Inserts the value of a system setting.
    Can be used in CSS files.
    Parameters
    $settingKey - Key of the system setting to insert.
    escape - By default, the raw value is output. If you need the value to be HTML-escaped, pass true for this parameter.
     
    {url="$url" csrf="[bool]" base="[string]" seoTemplate="[string]" seoTitle="[string]" seoTitles="[array]" protocol="[\IPS\Http\Url::PROTOCOL_AUTOMATIC|\IPS\Http\Url::PROTOCOL_HTTPS|\IPS\Http\Url::PROTOCOL_HTTP|\IPS\Http\Url::PROTOCOL_RELATIVE]" fragment="[string]" ref="[string]" plain="[bool]" ips="[string]" noprotocol="[bool]"}
    Generates an \IPS\Http\Url instance of a URL.
    Can be used in CSS files.
    Parameters
    csrf - Adds the CSRF Key to the query string
    base - The base to use, if this is an internal URL.
    seoTemplate - The SEO template for this URL to construct a friendly URL.
    seoTitle - The title to use for the friendly URL.
    seoTitles - An array of friendly URL titles. Not used if seoTitle is used.
    protocol - One of the \IPS\Http\Url::PROTOCOL_* constants to define the protocol to use.
    fragment - Adds a fragment to the end of the URL.
    ref - Sets a base64 encoded referring URL as a query string to the URL (used in conjunction with \IPS\Request::i()->referrer()).
    plain - To output the string value of the URL raw. If omitted, the string value is run through htmlspecialchars().
    ips - If this is an internal IPS URL to the documentation. Ignores all other parameters.
    noprotocol - Makes the URL protocol relative regardless of the defined protocol. This is deprecated, and \IPS\Http\Url::PROTOCOL_RELATIVE should be used instead.
  32. Like
    Rikki got a reaction from jeece76 for a guide, ips.ui.hovercard   
    Description
    The hovercard widget can be used to display a popup with remote content, which is attached to a trigger element.
     
    Example
    @todo
     
    Usage
    The hovercard widget is initialized by including the widget key attribute on a link:
    <a href='...' data-ipsHover>Hover on me</a> The URL that the link points to is also the URL that is called to fetch the hovercard content, by default.
     
    Options
    target
    (String; optional)
    If a URL other than the link's href should be used to load the hovercard content, it can be specified in this option.
     
    content
    (Mixed; optional)
    Sets the content of the hovercard. If a selector is provided, the contents of the matching element will be inserted into to hovercard. Alternatively, a string can be supplied which will be inserted into the hovercard. Using this option means remote content won't be loaded by the hovercard.
     
    timeout
    (Number; optional; default 0.75)
    The number of seconds between the user hovering on the element and the hovercard beginning to load (and conversely, hiding when the mouse leaves the element).
     
    attach
    (Selector; optional)
    The element that the hovercard will be attached to. If not specified, the element that the widget is initialized on will be used.
     
    width
    (Number; optional; default 300)
    The width in pixels at which the hovercard will display.
     
    onClick
    (Boolean; optional; default false)
    If true, the hovercard will be activated only when the user clicks on the element. By default, the hovercard will show on hover.
     
     
  33. Like
    Rikki got a reaction from jeece76 for a guide, Dropdown Menus   
    Description
    Dropdown menus allow users to select from a number of options. The markup is designed to work in tandem with the ips.ui.menu javascript module.
     
    Usage
    A menu consists of a trigger element, and the menu element itself:
    <!-- The trigger --> <a href='#elMyMenu_menu' id='elMyMenu'>Open Menu</a> <!-- The menu --> <ul id='elMyMenu_menu' class='ipsMenu'> ... </ul> The ID of the menu should be the ID of the trigger element, suffixed by _menu. If the trigger element is a link, its href should be an anchor to the ID of the menu element. This makes the menu accessible even when Javascript is disabled in the browser.
     
    Basic menu
    A basic menu might have the following markup:
    <ul class='ipsMenu ipsHide'> <li class='ipsMenu_item'><a href='#'>Item 1</a></li> <li class='ipsMenu_item'><a href='#'>Item 2</a></li> <li class='ipsMenu_item'><a href='#'>Item 3</a></li> <li class='ipsMenu_sep'><hr></li> <li class='ipsMenu_item'><a href='#'>Item 4</a></li> <li class='ipsMenu_item'><a href='#'>Item 5</a></li> </ul> This would display as follows: see example.
    Item 1 Item 2 Item 3 Item 4 Item 5 ipsMenu is the base class for the menu element. Items within the menu should have the class ipsMenu_item, with the link element inside of that. A separator item can be added by giving the item the class ipsMenu_sep, containing an <hr> element.
    Note that the positioning and stem is added automatically by the menu javascript module; it does not need to be manually specified. The stem can be removed, if necessary, by including the class ipsMenu_noStem on the menu element.
     
    Disabling menu items
    Individual menu items can be disabled by adding the class ipsMenu_itemDisabled to the list item: see example.
    Item 1 Disabled Item 2 Item 3 Note: Disabled items are not foolproof; in browsers that do not support the CSS pointer-events style, a click on a disabled item will still register. Ensure your javascript properly deals with disabled item clicks if necessary.
     
    Menu sizing
    By default, a menu will have no defined width. An additional classname can be specified on the menu element to determine how wide it should display.
    ipsMenu_auto - menu will appear as wide as necessary, though with a minimum width of 200px and a maximum width of 500px ipsMenu_narrow - 200 pixels wide ipsMenu_normal - 300 pixels wide ipsMenu_wide - 450 pixels wide  
    Selectable menus
    A selectable menu allows the user to toggle one or more of the menu items, useful for turning options on and off. For this functionality to work, the javascript module needs to be used.
    A menu can be made selectable by adding the classname ipsMenu_selectable. A menu item can be shown as selected by adding the classname ipsMenu_itemChecked to the list item.
    The markup for a selectable menu might look this:
    <ul id='elMenu2_menu' class='ipsMenu ipsMenu_normal ipsMenu_selectable ipsHide'> <li class='ipsMenu_item'><a href='#'>Item 1</a></li> <li class='ipsMenu_item ipsMenu_itemChecked'><a href='#'>Item 2</a></li> <li class='ipsMenu_item'><a href='#'>Item 3</a></li> </ul> This would display as follows: see example.
    Item 1 Item 2 Item 3  
    Sub-menus
    Submenus can be created by embedding menus within one another. To do so, simply include the ipsMenu_subItems class on the item that contains the submenu, and the submenu itself within the item. For example:
    <ul id='elMenu3_menu' class='ipsMenu ipsMenu_normal ipsHide'> <li class='ipsMenu_item'> <a href='#'>Item 1 (no children)</a> </li> <li class='ipsMenu_item ipsMenu_subItems'> <a href='#'>Item 2 (with children)</a> <ul class='ipsMenu ipsMenu_wide ipsHide'> <li class='ipsMenu_item'><a href='#'>Sub Item 1</a></li> <li class='ipsMenu_item'><a href='#'>Sub Item 2</a></li> <li class='ipsMenu_item'><a href='#'>Sub Item 3</a></li> </ul> </li> </ul> This would display as follows: see example.
    Item 1 (no children) Item 2 (with children) Sub Item 1 Sub Item 2 Sub Item 3  
  34. Like
    Rikki got a reaction from shahed for a guide, Handling right-to-left languages   
    The IPS Community Suite has built-in support for languages that use right-to-left text (including Arabic, Persian and others), and if you are creating a theme to share with others, you should ensure it is compatible with right-to-left display. Doing so is easy.
     
    RTL-specific CSS
    When RTL display is used, certain CSS properties need to be reversed; for example, if you position something left in LTR languages, when shown in RTL it would need to be positioned right instead.
    The global template in IPS4 always has the dir attribute specifying the text direction (the value is either ltr or rtl), and it is this attribute we can use to add direction-specific styles.
    Let's imagine you have some CSS in your theme like this:
    .yourClass { font-weight: bold; position: absolute; left: 15px; top: 15px; padding-left: 30px; } Some of these styles need to be separated out for RTL or the theme won't look right. So, by using the dir attribute on the html tag, what we instead need to write is:
    /* These styles are the same regardless of text-direction */ .yourClass { font-weight: bold; position: absolute; top: 15px; } /* LTR styles */ html[dir="ltr"] .yourClass { left: 15px; padding-left: 30px; } /* RTL styles */ html[dir="rtl"] .yourClass { right: 15px; padding-right: 30px; } That's it! RTL languages will now correctly position the element on the right-hand side of the screen, while LTR languages will show it on the left as expected.
    Whenever you use styles impacted by text direction, you should split them out in this way.
     
    RTL-specific icons
    The IPS Community Suite makes extensive use of FontAwesome icons. Some of the icons need to be flipped for RTL languages (such as arrows) and if you use the standard classnames (e.g. fa-caret-left), we automatically flip these so that they are correct for RTL languages.
    If you manually specify icons in your CSS classes using the unicode code, you will need to adjust them for RTL so that their opposite icon is used. For example, if you do this in your CSS:
    /* This uses the unicode for FA's 'angle-right' icon */ .nextLink:after { font-family: 'FontAwesome'; content: '\f105'; } You will need to change it to be:
    .nextLink:after { font-family: 'FontAwesome'; } html[dir="ltr"] .nextLink:after { content: '\f105'; } html[dir="rtl"] .nextLink:after { content: '\f104'; }  
    Consider your Javascript
    This usually will not require any action. However, if you have any custom JavaScript which adds user interaction, consider if any changes need to be made. For example, if you have a menu which opens from the left, it may need to open from the right. If you are only using the UI widgets already in the IPS Community Suite, these already make all such considerations so no action will be necessary.
  35. Like
    Rikki got a reaction from TSP for a guide, Targeting elements on specific pages with CSS   
    Occasionally, you'll want to be able to change the style of a particular element on a particular page, without affecting similar elements on other pages. For example, lets say you wanted to change how the .ipsPageHeader element looks in topic view, to make the title bigger, but without changing it for all other pages that also use .ipsPageHeader.
     
    Adding a classname - the wrong way
    One method would be to edit the template for topic view, add a classname to the element, and then create a style using that new classname as the selector. This works, but it has a drawback - because you've edited the template, IPS4 won't be able to automatically update it for you when you upgrade to newer versions of the IPS Community Suite. We always suggest you try and avoid editing templates directly, for this reason.
     
    Using page-specific selectors - the right way
    There's a better way - every page in IPS4 includes some special attributes on the body tag that identify the app, module and controller being viewed. You can use these to write a CSS selector to only target pages that match the ones you want. Going back to our example, we could target .ipsPageHeader in topic view like so:
    body[data-pageapp="forums"][data-pagemodule="forums"][data-pagecontroller="topic"] .ipsPageHeader { ...your styles } This works because topic view is generated by the topic controller, in the forums module, in the forums app. All pages in the IPS Community Suite follow this controller/module/application structure.
    You can mix and match these. If you want to style all page headers in the forums app only, you could simplify the above to:
    body[data-pageapp="forums"] .ipsPageHeader { ...your styles } You can find out the right values to use by going to the page you want to target, viewing the source in a tool like Web Inspector, and finding the body tag - look for the special data-page* attributes that are used for that page.
    By including these styles in your custom.css file in your theme, you can target specific elements on specific pages, without making it difficult to upgrade your community later.
  36. Like
    Rikki got a reaction from Meddysong for a guide, Targeting elements on specific pages with CSS   
    Occasionally, you'll want to be able to change the style of a particular element on a particular page, without affecting similar elements on other pages. For example, lets say you wanted to change how the .ipsPageHeader element looks in topic view, to make the title bigger, but without changing it for all other pages that also use .ipsPageHeader.
     
    Adding a classname - the wrong way
    One method would be to edit the template for topic view, add a classname to the element, and then create a style using that new classname as the selector. This works, but it has a drawback - because you've edited the template, IPS4 won't be able to automatically update it for you when you upgrade to newer versions of the IPS Community Suite. We always suggest you try and avoid editing templates directly, for this reason.
     
    Using page-specific selectors - the right way
    There's a better way - every page in IPS4 includes some special attributes on the body tag that identify the app, module and controller being viewed. You can use these to write a CSS selector to only target pages that match the ones you want. Going back to our example, we could target .ipsPageHeader in topic view like so:
    body[data-pageapp="forums"][data-pagemodule="forums"][data-pagecontroller="topic"] .ipsPageHeader { ...your styles } This works because topic view is generated by the topic controller, in the forums module, in the forums app. All pages in the IPS Community Suite follow this controller/module/application structure.
    You can mix and match these. If you want to style all page headers in the forums app only, you could simplify the above to:
    body[data-pageapp="forums"] .ipsPageHeader { ...your styles } You can find out the right values to use by going to the page you want to target, viewing the source in a tool like Web Inspector, and finding the body tag - look for the special data-page* attributes that are used for that page.
    By including these styles in your custom.css file in your theme, you can target specific elements on specific pages, without making it difficult to upgrade your community later.
  37. Like
    Rikki got a reaction from Carlos S. for a guide, Introduction to Pages   
    Introduction
    Pages is our application that is designed to allow you to build custom areas of your community. These could range from custom reusable blocks to use in your sidebar, all the way up to complex applications built using our databases feature.
    Whereas our other applications provide a regimented (although customizable) front-end that's ready to use right after installation, Pages is a little different. Think of it more as a toolbox - it provides features that you use to build your own front-ends. Therefore, you need to put in some work once you start using it before you have anything to make live. This guide will cover the core concepts and features in Pages to help you get started.
     
    Who is Pages for?
    Pages has features for everyone! It has easy-to-use features like drag'n'drop page building, but under the hood, the entire IPS4 framework is available for power users to take advantage of. The wider your knowledge of HTML & PHP, the more advanced solutions you'll be able to develop, although no experience of HTML & PHP is required to get started with Pages!
      Pages
  38. Like
    Rikki got a reaction from SlimTall for a guide, Changing FontAwesome icons per-forum   
    By default, we use the 'comments' icon from FontAwesome to represent forums on the read/unread badges. IPS4 also includes an option to upload an image that will be used instead of the icon. But what if you want to use a different FontAwesome icon for each forum?
    The good news is this is possible using some custom CSS. Each forum row in the index template includes a data attribute with the forum ID, meaning we can write a style to specifically target each individual forum and overwrite the icon it uses.
    Note: Although this method isn't terribly complex, it does require editing custom CSS and working with unicode characters.
     
    Determining the icon unicode value
    The method we're going to use involves replacing the icon using a CSS rule, rather than changing the icon classname in the HTML. The reason we take this approach is it won't make upgrading your templates difficult later - our custom CSS persist through IPS4 versions easily.
    What this means however is that we need to identify the unicode value that FontAwesome assigns to the icons we want to use.
    To do so, head over to the FontAwesome icon list on this page. Locate the icon you'd like to use, and click it. On the information page, you'll see the unicode value for the icon. Make a note of this code. For example:

    Do this for each icon you'll want to use.
     
    Adding the CSS
    We're going to add our CSS to our custom.css file so that it persists through upgrades. In the AdminCP, go to Customizations -> Themes, and click the code edit icon next to the theme you want to change. On the CSS tab, open the custom.css file:

    The rule we need to use looks like this:
    [data-forumid="..."] .fa-comments:before { content: "\f123"; } You'll need to adjust this code to include the forum ID for the forum you want to change. You can find the forum ID by hovering on the link to the forum, and noting the number you see in the URL: 

    You'll also need to replace the f123 unicode value with the one for the icon you want to use that you noted earlier.
     
    Example
    Let's say we have forum ID's 1 and 2, and we want to use FontAwesome's bicycle and car icons, respectively. We note the unicode values for those icons, which are f206 and f1b9.
    The CSS we'd add looks like this:
    [data-forumid="1"] .fa-comments:before { content: "\f206"; } [data-forumid="2"] .fa-comments:before { content: "\f1b9"; } Once we save it, we can see the result:

  39. Like
    Rikki got a reaction from SlimTall for a guide, Setting up the database   
    The Release Notes section is built using the Database feature in Pages, so the first step is simply to create the database we'll be using.
    What are databases?
    The Databases feature in Pages gives you the tools you need to create your own custom data-driven sections of your community. You define the settings and fields in the database, and Pages gives you support for categories, comments, reviews, ratings and more - just like full IPS Community Suite applications. Since you have full control over the templates for each database (and even each category within the database). it's possible to create some advanced pages.
     
    Creating the database
    Let's set up the database first. In the AdminCP, go to Pages -> Content -> Databases and click Create New. You'll see a tabbed form that configures how this database will work.

    Creating the database
     
    Start with the basics: enter Release Notes for the name (this is how the suite will refer to your new section in menus etc.), and enter a description if you wish.
    The next two options configure how the database uses categories. For our purposes, we don't need categories at all - recall that we simply show a table of releases. Upon selecting that option, you'll see another option to show a record list, which is precisely what we want here.

    Database Settings
    Below these, you'll see settings for templates. We don't need to worry about these for now - we'll be creating our own templates later.
    The final step on this tab is to set a database key. This is just a way for pages in the suite to find the correct database later - it isn't shown to users. Entering release-notes is fine.
    Languages
    The languages tab is where we configure how the database will refer to our records. It means it can show things like "1 new release" instead of the generic "1 new record". We'll set them to (in this order):
    release
    releases
    Release
    Releases
    a release
     
    Options
    On the options tab we'll configure some settings for the database. We're going to keep the default settings with the following exceptions:
    Disable comments
    We won't be allowing comments at all in our Release Notes section, so we'll disable this functionality from the outset Disable reviews
    As above Disable "enable record image upload"
    We won't be attaching images to release notes, so we can disable this feature too Note that later we'll be sorting by a field we've yet to create, but for now the default choice is fine.
    Forums
    We aren't going to be making use of the Forums integration here, so we can safely ignore this tab.
    Page
    Our database needs to live on a page within our website in order to be shown to users. You can create a page separately in the AdminCP and insert the database into it, but since we're creating the database now, we can do it in one go to save time. We're going to configure our page like so:
     

    Page Settings
    The key details here are:
    We're creating a new page for the database We've set the name to "Release Notes". This is how the page is referred to in links and menus, and will also be the browser title on this page. We've set the filename to "release-notes". This forms the URL to the page; in this case, it'll end up being <your community url>/release-notes/. We've chosen to create the page using Manual HTML, which means we will write the HTML to display the page. The alternative is to use the easy Page Builder, which enables you to drag and drop blocks into the page. You can use whichever you are more comfortable with. We're using the suite HTML wrapper. This is the header and footer of your site that our page will use. With this disabled, we'd be responsible for writing the entire page from scratch, which we don't want to do in this case. Permissions
    When you save the database, you'll see the permissions matrix to configure what each can do. We want to allow all groups to see the database and records, but we're only going to allow staff to add and edit records (and remember, comments & reviews are disabled anyway):

    Database Permissions
    That's it - you can save the form, and your database will be created. Next we'll move on to creating our fields.
    Creating Custom Fields Introduction
  40. Like
    Rikki got a reaction from Meddysong for a guide, Styling CKEditor   
    The IPS Community Suite uses CKEditor to power its rich text editing capabilities. Often, when developing a theme for you own community or for distribution, you'll also want to style the editor to match.
    CKEditor itself is a very large and complex project. It has many hundreds of CSS classes, and explaining how to style each part of the editor is beyond the scope of this guide. We recommend you check out CKEditor's website if you need more information.
    That said, here's some tips to guide you.
     
    Using custom.css to style the editor
    Prior to IPS 4.1, we used CKEditor's older iframe mode. What this meant is that the entire text editor existed inside of an iframe on the page (although this was seamless and transparent to users). Since styles of a parent page do not apply to the contents of iframes, the only way to style the editor was to edit the CKEditor skin that we shipped with the product. This meant working outside of the IPS4 theme system, but more importantly it made distributing your changes more difficult because you'd also have to distribute your CKEditor skin.
    In IPS 4.1 onwards, we use the newer div mode. Instead of using an iframe, the editor is built inside a div element right on the page. This is great news for themers, because it means the CSS styles you create within IPS4 will be inherited by CKEditor automatically.
    So, to start styling the editor, you can simply open your custom.css file in your theme, and using a tool such as Google Chrome's Web Inspector (or the equivalent in your browser of choice), inspect the HTML that CKEditor generates and use that to develop your styling. When you save your custom.css file, you'll see it applies to the editor too.

    Above: inspecting CKEditor's generated HTML with Web Inspector allows you to see which CSS styles (right) are being applied to each part of the editor, helping you identify which class names you should be using in your own CSS.
     
    Or build a standalone CKEditor skin
    If you intend to make more substantial changes to the editor, you may still want to consider developing it as an actual CKEditor skin instead. CKEditor has a very mature skin framework that can be used for advanced changes. Consult the CKEditor for more information on creating a skin.
    If you go this route, you would export the CKEditor skin, and ship it with your IPS Community Suite theme. When an administrator installs your theme, they can install the CKEditor skin in the AdminCP too.
     
    So, that seems quite straightforward - in almost all cases, simply edit the custom.css file you use in your theme, and you can customize CKEditor to match your theme!
     
    But, there's gotchas...
    There are exceptions, of course. Even in div-mode, CKEditor still generates some iframes. For example, when you click a dropdown menu in the editor (e.g. Font), CKEditor actually builds an iframe for the menu.

    This introduces the same problems we discussed above, again!
    Unfortunately, there is no simple answer here. As before, styles you build into your custom.css file won't apply to these special areas where CKEditor uses an iframe. For many theme designers, this won't be a huge problem - being able to edit the 95% of CKEditor available to custom.css will be sufficient. But if you really do need to style the contents of those iframes, the only option is to do it within CKEditor's own skin system (since it loads those CSS files within its iframe).
    This isn't too problematic if you're only concerned with styling your own community. The CSS files CKEditor uses can be found in /applications/core/interface/ckeditor/ckeditor/skins/ips (if your theme uses the default CKEditor theme we provide). Edit the editor.css file in this directory to adjust the styles (this is a compressed CSS file, so add your own CSS at the end - don't edit existing CSS in the file!).
    If you plan to distribute your IPS4 theme, however, and you need to style these areas of CKEditor that still exist in an iframe, you'll need to go back to using CKEditor's skin system, and distributing a CKEditor skin with your theme.
  41. Like
    Rikki got a reaction from SlimTall for a guide, Templates, CSS & JS   
    Templates, CSS and JS files are the means by which coders can take the default output of the various parts of Pages, and customize them to build unique parts of their site.
    Note: only those familiar with HTML, CSS and some PHP should consider modifying their templates. Since they involve editing code, it's easy to break the output of your site unintentionally!
     
    Types of template in Pages
    Templates are the key to customizing areas of your Pages website so that they're unique to your site and to your particular use of them. There's three primary types of template you can customize:
    Database templates
    Databases templates let you change the output of just about every part of your databases. There's four main types of template: Category Index
    The templates that render the category index of a database, and subcategories when browsing the record listing. Listing
    Templates that render the record listing Display
    Templates that render record view itself, including comments & reviews Form
    Templates for the add/edit form, allowing you to customize this form per-database Page templates
    By default, a page will use the suite wrapper, which includes the header, navigation, user bar etc. leaving your page content to control the actual content area. However, you can instead choose to use a custom page wrapper, allowing you to control the entire output of the page. Wrappers are created as page templates, and selected when you create your page. Block templates
    When you create a plugin block showing a feed of data, IPS4 uses a default template. You can however customize this template or create a new one, allowing each block to have a unique appearance.  
    What can blocks contain?
    Blocks can contain the full range of IPS4 template syntax, which affords great flexibility. The data available to each template will depend on its type (for example, a database listing template will receive data from the database category, but a block template will receive data that matches the block's filters), but all templates can access the full underlying IPS4 PHP framework.
     
    Creating & Editing templates
    Database and page templates are managed in the Pages template editor, accessed by navigating to Pages -> Templates in the AdminCP and clicking the New button.
    Default block templates are also managed in the template editor as above, but can also be customized per-block within the block configuration themselves, by going to Pages -> Blocks in the AdminCP and then editing the block in question. 
     
    CSS & JS files
    To fully customize sections created with Pages, it's often desirable to add custom CSS and Javascript. Pages offers a built-in way to write and use these resources and then assign them to a page for use.
    CSS and JS resources within Pages are managed by navigating to Pages -> Templates in the AdminCP, and then clicking the CSS or JS tabs in the editor. New resources can be added by clicking the New button.
    To assign them to a page, simply select them on the Includes tab when creating or editing a page in the AdminCP.
  42. Like
    Rikki got a reaction from opentype for a guide, (Advanced) Building dynamic blocks based on the page being viewed   
    For more advanced sites built with Pages, you may want to change the output of a custom HTML or PHP block depending on which page the user is viewing. For example, if you have a custom menu, you may want to highlight the active item.
    We can implement this in Pages by checking the underlying page URL parameters. Although you access a page with a friendly URL (FURL) like http://<yourcommunity>/section/page, behind the scenes this is mapped to a raw URL, such as http://<yourcommunity>/index.php?app=cms&module=pages&controller=page&path=/section/page. Notice the path parameter allows us to identify which page we're accessing. When we access the \IPS\Request::i() object, we can compare against this parameter, like so:
    {{if strpos( \IPS\Request::i()->path, 'section/page' ) !== FALSE}} <!-- We know the user is on /section/page --> {{elseif strpos( \IPS\Request::i()->path, 'othersection/otherpage' ) !== FALSE}} <!-- We know the user is on /othersection/otherpage --> {{endif}} Note that for reliability, we're using PHP's strpos function to check for the presence of the page URL in the path parameter, rather than a simple comparison.
    Example
    Let's assume we've created a Manual HTML block, we're adding HTML to show a menu, and we want to highlight the correct item based on the page. Here's what our block contents might look like:
    <ul class='ipsList_inline cMyMenu'> <li {{if strpos( \IPS\Request::i()->path, 'help/home' ) !== FALSE}}class='active'{{endif}}> <a href='/help/home'>Home</a> </li> <li {{if strpos( \IPS\Request::i()->path, 'help/faq' ) !== FALSE}}class='active'{{endif}}> <a href='/help/faq'>FAQ</a> </li> <li {{if strpos( \IPS\Request::i()->path, 'help/tutorials' ) !== FALSE}}class='active'{{endif}}> <a href='/help/tutorials'>Tutorials</a> </li> </ul> If we had many items to show, it would get tedious to list them all like this. We could instead do it as a loop:
    // Using a PHP variable to store an array of pages => page names that we'll loop over {{$myPages = array('help/home' => "Home", 'help/faq' => "FAQ", 'help/tutorials' => "Tutorials", 'help/qna/listing' => "Questions", 'help/qna/recent' => "Recent Questions", 'help/contact' => "Contact Us");}} <ul class='ipsList_inline cMyMenu'> {{foreach $myPages as $url => $title}} <li {{if strpos( \IPS\Request::i()->path, $url ) !== FALSE}}class='active'{{endif}}> <a href='{$url}'>{$title}</a> </li> {{endforeach}} </ul> Now to add new items to our custom menu, we just have to add them to the array.
  43. Like
    Rikki got a reaction from dean84 for a guide, Changing FontAwesome icons per-forum   
    By default, we use the 'comments' icon from FontAwesome to represent forums on the read/unread badges. IPS4 also includes an option to upload an image that will be used instead of the icon. But what if you want to use a different FontAwesome icon for each forum?
    The good news is this is possible using some custom CSS. Each forum row in the index template includes a data attribute with the forum ID, meaning we can write a style to specifically target each individual forum and overwrite the icon it uses.
    Note: Although this method isn't terribly complex, it does require editing custom CSS and working with unicode characters.
     
    Determining the icon unicode value
    The method we're going to use involves replacing the icon using a CSS rule, rather than changing the icon classname in the HTML. The reason we take this approach is it won't make upgrading your templates difficult later - our custom CSS persist through IPS4 versions easily.
    What this means however is that we need to identify the unicode value that FontAwesome assigns to the icons we want to use.
    To do so, head over to the FontAwesome icon list on this page. Locate the icon you'd like to use, and click it. On the information page, you'll see the unicode value for the icon. Make a note of this code. For example:

    Do this for each icon you'll want to use.
     
    Adding the CSS
    We're going to add our CSS to our custom.css file so that it persists through upgrades. In the AdminCP, go to Customizations -> Themes, and click the code edit icon next to the theme you want to change. On the CSS tab, open the custom.css file:

    The rule we need to use looks like this:
    [data-forumid="..."] .fa-comments:before { content: "\f123"; } You'll need to adjust this code to include the forum ID for the forum you want to change. You can find the forum ID by hovering on the link to the forum, and noting the number you see in the URL: 

    You'll also need to replace the f123 unicode value with the one for the icon you want to use that you noted earlier.
     
    Example
    Let's say we have forum ID's 1 and 2, and we want to use FontAwesome's bicycle and car icons, respectively. We note the unicode values for those icons, which are f206 and f1b9.
    The CSS we'd add looks like this:
    [data-forumid="1"] .fa-comments:before { content: "\f206"; } [data-forumid="2"] .fa-comments:before { content: "\f1b9"; } Once we save it, we can see the result:

  44. Like
    Rikki got a reaction from Heosforo for a guide, Changing FontAwesome icons per-forum   
    By default, we use the 'comments' icon from FontAwesome to represent forums on the read/unread badges. IPS4 also includes an option to upload an image that will be used instead of the icon. But what if you want to use a different FontAwesome icon for each forum?
    The good news is this is possible using some custom CSS. Each forum row in the index template includes a data attribute with the forum ID, meaning we can write a style to specifically target each individual forum and overwrite the icon it uses.
    Note: Although this method isn't terribly complex, it does require editing custom CSS and working with unicode characters.
     
    Determining the icon unicode value
    The method we're going to use involves replacing the icon using a CSS rule, rather than changing the icon classname in the HTML. The reason we take this approach is it won't make upgrading your templates difficult later - our custom CSS persist through IPS4 versions easily.
    What this means however is that we need to identify the unicode value that FontAwesome assigns to the icons we want to use.
    To do so, head over to the FontAwesome icon list on this page. Locate the icon you'd like to use, and click it. On the information page, you'll see the unicode value for the icon. Make a note of this code. For example:

    Do this for each icon you'll want to use.
     
    Adding the CSS
    We're going to add our CSS to our custom.css file so that it persists through upgrades. In the AdminCP, go to Customizations -> Themes, and click the code edit icon next to the theme you want to change. On the CSS tab, open the custom.css file:

    The rule we need to use looks like this:
    [data-forumid="..."] .fa-comments:before { content: "\f123"; } You'll need to adjust this code to include the forum ID for the forum you want to change. You can find the forum ID by hovering on the link to the forum, and noting the number you see in the URL: 

    You'll also need to replace the f123 unicode value with the one for the icon you want to use that you noted earlier.
     
    Example
    Let's say we have forum ID's 1 and 2, and we want to use FontAwesome's bicycle and car icons, respectively. We note the unicode values for those icons, which are f206 and f1b9.
    The CSS we'd add looks like this:
    [data-forumid="1"] .fa-comments:before { content: "\f206"; } [data-forumid="2"] .fa-comments:before { content: "\f1b9"; } Once we save it, we can see the result:

  45. Like
    Rikki got a reaction from Kjell Iver Johansen for a guide, Changing FontAwesome icons per-forum   
    By default, we use the 'comments' icon from FontAwesome to represent forums on the read/unread badges. IPS4 also includes an option to upload an image that will be used instead of the icon. But what if you want to use a different FontAwesome icon for each forum?
    The good news is this is possible using some custom CSS. Each forum row in the index template includes a data attribute with the forum ID, meaning we can write a style to specifically target each individual forum and overwrite the icon it uses.
    Note: Although this method isn't terribly complex, it does require editing custom CSS and working with unicode characters.
     
    Determining the icon unicode value
    The method we're going to use involves replacing the icon using a CSS rule, rather than changing the icon classname in the HTML. The reason we take this approach is it won't make upgrading your templates difficult later - our custom CSS persist through IPS4 versions easily.
    What this means however is that we need to identify the unicode value that FontAwesome assigns to the icons we want to use.
    To do so, head over to the FontAwesome icon list on this page. Locate the icon you'd like to use, and click it. On the information page, you'll see the unicode value for the icon. Make a note of this code. For example:

    Do this for each icon you'll want to use.
     
    Adding the CSS
    We're going to add our CSS to our custom.css file so that it persists through upgrades. In the AdminCP, go to Customizations -> Themes, and click the code edit icon next to the theme you want to change. On the CSS tab, open the custom.css file:

    The rule we need to use looks like this:
    [data-forumid="..."] .fa-comments:before { content: "\f123"; } You'll need to adjust this code to include the forum ID for the forum you want to change. You can find the forum ID by hovering on the link to the forum, and noting the number you see in the URL: 

    You'll also need to replace the f123 unicode value with the one for the icon you want to use that you noted earlier.
     
    Example
    Let's say we have forum ID's 1 and 2, and we want to use FontAwesome's bicycle and car icons, respectively. We note the unicode values for those icons, which are f206 and f1b9.
    The CSS we'd add looks like this:
    [data-forumid="1"] .fa-comments:before { content: "\f206"; } [data-forumid="2"] .fa-comments:before { content: "\f1b9"; } Once we save it, we can see the result:

  46. Like
    Rikki got a reaction from ABGenc for a guide, Changing FontAwesome icons per-forum   
    By default, we use the 'comments' icon from FontAwesome to represent forums on the read/unread badges. IPS4 also includes an option to upload an image that will be used instead of the icon. But what if you want to use a different FontAwesome icon for each forum?
    The good news is this is possible using some custom CSS. Each forum row in the index template includes a data attribute with the forum ID, meaning we can write a style to specifically target each individual forum and overwrite the icon it uses.
    Note: Although this method isn't terribly complex, it does require editing custom CSS and working with unicode characters.
     
    Determining the icon unicode value
    The method we're going to use involves replacing the icon using a CSS rule, rather than changing the icon classname in the HTML. The reason we take this approach is it won't make upgrading your templates difficult later - our custom CSS persist through IPS4 versions easily.
    What this means however is that we need to identify the unicode value that FontAwesome assigns to the icons we want to use.
    To do so, head over to the FontAwesome icon list on this page. Locate the icon you'd like to use, and click it. On the information page, you'll see the unicode value for the icon. Make a note of this code. For example:

    Do this for each icon you'll want to use.
     
    Adding the CSS
    We're going to add our CSS to our custom.css file so that it persists through upgrades. In the AdminCP, go to Customizations -> Themes, and click the code edit icon next to the theme you want to change. On the CSS tab, open the custom.css file:

    The rule we need to use looks like this:
    [data-forumid="..."] .fa-comments:before { content: "\f123"; } You'll need to adjust this code to include the forum ID for the forum you want to change. You can find the forum ID by hovering on the link to the forum, and noting the number you see in the URL: 

    You'll also need to replace the f123 unicode value with the one for the icon you want to use that you noted earlier.
     
    Example
    Let's say we have forum ID's 1 and 2, and we want to use FontAwesome's bicycle and car icons, respectively. We note the unicode values for those icons, which are f206 and f1b9.
    The CSS we'd add looks like this:
    [data-forumid="1"] .fa-comments:before { content: "\f206"; } [data-forumid="2"] .fa-comments:before { content: "\f1b9"; } Once we save it, we can see the result:

  47. Like
    Rikki got a reaction from Square Wheels for a guide, Changing FontAwesome icons per-forum   
    By default, we use the 'comments' icon from FontAwesome to represent forums on the read/unread badges. IPS4 also includes an option to upload an image that will be used instead of the icon. But what if you want to use a different FontAwesome icon for each forum?
    The good news is this is possible using some custom CSS. Each forum row in the index template includes a data attribute with the forum ID, meaning we can write a style to specifically target each individual forum and overwrite the icon it uses.
    Note: Although this method isn't terribly complex, it does require editing custom CSS and working with unicode characters.
     
    Determining the icon unicode value
    The method we're going to use involves replacing the icon using a CSS rule, rather than changing the icon classname in the HTML. The reason we take this approach is it won't make upgrading your templates difficult later - our custom CSS persist through IPS4 versions easily.
    What this means however is that we need to identify the unicode value that FontAwesome assigns to the icons we want to use.
    To do so, head over to the FontAwesome icon list on this page. Locate the icon you'd like to use, and click it. On the information page, you'll see the unicode value for the icon. Make a note of this code. For example:

    Do this for each icon you'll want to use.
     
    Adding the CSS
    We're going to add our CSS to our custom.css file so that it persists through upgrades. In the AdminCP, go to Customizations -> Themes, and click the code edit icon next to the theme you want to change. On the CSS tab, open the custom.css file:

    The rule we need to use looks like this:
    [data-forumid="..."] .fa-comments:before { content: "\f123"; } You'll need to adjust this code to include the forum ID for the forum you want to change. You can find the forum ID by hovering on the link to the forum, and noting the number you see in the URL: 

    You'll also need to replace the f123 unicode value with the one for the icon you want to use that you noted earlier.
     
    Example
    Let's say we have forum ID's 1 and 2, and we want to use FontAwesome's bicycle and car icons, respectively. We note the unicode values for those icons, which are f206 and f1b9.
    The CSS we'd add looks like this:
    [data-forumid="1"] .fa-comments:before { content: "\f206"; } [data-forumid="2"] .fa-comments:before { content: "\f1b9"; } Once we save it, we can see the result:

  48. Like
    Rikki got a reaction from BN_IT_Support for a guide, Adding custom editor buttons   
    If an existing CKEditor plugin isn't available that meets your needs, another alternative that may be suitable is to create a custom button.
     
    What can custom buttons do?
    Custom buttons allow you to create blocks of HTML that are inserted by clicking a button on the editor toolbar. The blocks you create can accept content that users can enter.
    Custom buttons don't have the capabilities of a full CKEditor plugin - they can't be dynamic or use Javascript, for example. But for formatting text the user enters, a custom button may be the best choice.
    Note: although custom buttons tend to be simple, we recommend you have knowledge of HTML, or seek assistance from our peer-to-peer forums.
     
    Creating a custom button
    To create a custom button, navigate to Customization -> Editor -> Toolbars. Click the Add Button button in the header, and then the Custom tab. The form you see has the following fields:
    Button title
    The title seen by users when they hover over the button in the editor Icon
    A small image file that will act at the button icon on the editor. For retina support, upload an icon twice as big as you'd like it to display; it will be resized down by the browser and therefore show high-res. Type
    Three types of content are supported, and they roughly mimic the three types of element display in HTML: Inline - used when the inserted HTML exists somewhere in a line of text. Does not create a new line for the content. Single line block - designed for single lines (e.g. headers), and puts the block on a new line Block - used for multiple lines, and puts the block on a new line Use option
    A custom button can optionally accept a value from the user (aside from what they can type as normal inside the block itself). This option will appear as a popup dialog when the user clicks the button in the editor, and the value they enter is passed into the block when it is rendered. With this field enabled, you'll see an additional setting: Option label
    The text shown to the user requesting a value for the option. HTML
    The actual HTML the button will render in the editor when used. Generally, any HTML is supported but it must be valid. Within this HTML, a couple of special tags can be used: {option}
    If the option is used, this tag is replaced with the value the user entered, as-is. {content}
    If your button will allow the user to type within the generated HTML, insert this tag where the user should be able to type. Click the Save button to create the button. Your icon will be shown on the Buttons Not On Editor toolbar, and from here you can drag it to your live toolbars and configure it as normal.
     
    Using custom styles
    We don't recommend using inline styles in your HTML, because it will be almost impossible for you to update later (posts are built at save-time, not display-time, so if you update a custom button, old posts won't reflect those changes).
    Instead, we suggest using classnames, and adding styles for those classnames in your custom.css theme file. This way, you can update the styles later, and old posts will also reflect the changes.
     
    An example
    Within this documentation we have tip boxes like this:
    Tip This is a tip
    This is a custom editor button we've created that is available to staff. Here's the configuration we used to create this button:
    Button title
    Tip Icon
    Type
    Block Use option
    No HTML <div class='docsBox docsBox_tip'> <div class='docsBox_header'>Tip</div> <div class='docsBox_body'> <div class='ipsType_richText ipsType_break ipsContained'> {content} </div> </div> </div>  
    We then add these styles to our custom.css CSS file:
    .docsBox_header { padding: 5px 10px; color: #fff; font-weight: 500; font-size: 15px; } .docsBox_body { padding: 10px; font-size: 13px; line-height: 1.4; } .docsBox_tip .docsBox_header { background: #2E7D32; } .docsBox_tip .docsBox_body { background: #E8F5E9; } .docsBox_tip .docsBox_body .ipsType_richText { color: #1B5E20; }  
  49. Like
    Rikki got a reaction from Devin De Frisco for a guide, Adding custom editor buttons   
    If an existing CKEditor plugin isn't available that meets your needs, another alternative that may be suitable is to create a custom button.
     
    What can custom buttons do?
    Custom buttons allow you to create blocks of HTML that are inserted by clicking a button on the editor toolbar. The blocks you create can accept content that users can enter.
    Custom buttons don't have the capabilities of a full CKEditor plugin - they can't be dynamic or use Javascript, for example. But for formatting text the user enters, a custom button may be the best choice.
    Note: although custom buttons tend to be simple, we recommend you have knowledge of HTML, or seek assistance from our peer-to-peer forums.
     
    Creating a custom button
    To create a custom button, navigate to Customization -> Editor -> Toolbars. Click the Add Button button in the header, and then the Custom tab. The form you see has the following fields:
    Button title
    The title seen by users when they hover over the button in the editor Icon
    A small image file that will act at the button icon on the editor. For retina support, upload an icon twice as big as you'd like it to display; it will be resized down by the browser and therefore show high-res. Type
    Three types of content are supported, and they roughly mimic the three types of element display in HTML: Inline - used when the inserted HTML exists somewhere in a line of text. Does not create a new line for the content. Single line block - designed for single lines (e.g. headers), and puts the block on a new line Block - used for multiple lines, and puts the block on a new line Use option
    A custom button can optionally accept a value from the user (aside from what they can type as normal inside the block itself). This option will appear as a popup dialog when the user clicks the button in the editor, and the value they enter is passed into the block when it is rendered. With this field enabled, you'll see an additional setting: Option label
    The text shown to the user requesting a value for the option. HTML
    The actual HTML the button will render in the editor when used. Generally, any HTML is supported but it must be valid. Within this HTML, a couple of special tags can be used: {option}
    If the option is used, this tag is replaced with the value the user entered, as-is. {content}
    If your button will allow the user to type within the generated HTML, insert this tag where the user should be able to type. Click the Save button to create the button. Your icon will be shown on the Buttons Not On Editor toolbar, and from here you can drag it to your live toolbars and configure it as normal.
     
    Using custom styles
    We don't recommend using inline styles in your HTML, because it will be almost impossible for you to update later (posts are built at save-time, not display-time, so if you update a custom button, old posts won't reflect those changes).
    Instead, we suggest using classnames, and adding styles for those classnames in your custom.css theme file. This way, you can update the styles later, and old posts will also reflect the changes.
     
    An example
    Within this documentation we have tip boxes like this:
    Tip This is a tip
    This is a custom editor button we've created that is available to staff. Here's the configuration we used to create this button:
    Button title
    Tip Icon
    Type
    Block Use option
    No HTML <div class='docsBox docsBox_tip'> <div class='docsBox_header'>Tip</div> <div class='docsBox_body'> <div class='ipsType_richText ipsType_break ipsContained'> {content} </div> </div> </div>  
    We then add these styles to our custom.css CSS file:
    .docsBox_header { padding: 5px 10px; color: #fff; font-weight: 500; font-size: 15px; } .docsBox_body { padding: 10px; font-size: 13px; line-height: 1.4; } .docsBox_tip .docsBox_header { background: #2E7D32; } .docsBox_tip .docsBox_body { background: #E8F5E9; } .docsBox_tip .docsBox_body .ipsType_richText { color: #1B5E20; }  
×
×
  • Create New...