Jump to content

Rikki

Members
  • Posts

    24,413
  • Joined

  • Last visited

  • Days Won

    84

Reputation Activity

  1. Like
    Rikki got a reaction from 60kell for a guide, Buttons   
    Basics
    The button classes described here can be applied to any element, although typically would be applied to an element like a, input[type="submit"] or button so that the user can interact with it.
    As a minimum, a button should receive the basic ipsButton class, plus a size class and a style class (explained below).
     
    Button styles
    ipsButton_normal
    Normal button ipsButton_primary
    Primary button ipsButton_alternate
    Alternate button ipsButton_important
    Important button ipsButton_light
    Light button ipsButton_veryLight
    Very light button ipsButton_overlaid
    Overlaid button ipsButton_link
    Link button  
    Button sizes
    ipsButton_medium
    Medium button ipsButton_verySmall
    Very small button ipsButton_small
    Small button ipsButton_large
    Large button ipsButton_veryLarge
    Very large button ipsButton_fullWidth
    Can be combined with another size, above.
    Full width button  
    Disabled buttons
    Buttons can be visually disabled either by adding the class ipsButton_disabled, or, on relevant input elements, adding the disabled property. For example:
    <a href='#' class='ipsButton ipsButton_normal ipsButton_medium ipsButton_disabled'>Disabled button (link)</a> <input type='submit' class='ipsButton ipsButton_normal ipsButton_medium' disabled value='Disabled button (input)'> These would render like so:
    Disabled button (link)  
    Split buttons
    Split buttons allow you to create toolbars easily by specifying a list of buttons that display joined to each other.
    They are created by specifying the class ipsButton_split on a wrapper element containing two or more buttons. The wrapper element can be a <ul> tag, or any other that makes sense for your use.
    All of the buttons in a split button group should be the same size, otherwise results are unpredictable. Different styles can be used on each button, though.
    <ul class='ipsButton_split'> <li><a href='#' class='ipsButton ipsButton_small ipsButton_primary'>Button 1</a></li> <li><a href='#' class='ipsButton ipsButton_small ipsButton_light'>Button 2</a></li> <li><a href='#' class='ipsButton ipsButton_small ipsButton_light'>Button 3</a></li> </ul> Button 1 Button 2 Button 3  
  2. Like
    Rikki got a reaction from citrixws for a guide, Common logic checks using HTML Logic   
    HTML Logic is a very powerful way of conditionally showing different elements in your theme, depending on the values of certain properties. Since the entire IPS4 framework is available within a logic expression, there's a lot of scope for using different kinds of data to determine what should show.
    In this guide we'll provide a range of examples of common logic checks you might want to do. Even if the exact expression you need isn't listed here, it should provide a good starting point to help you write your own expressions.
     
    Logic Recap
    Let's quickly recap how HTML Logic works. For a more complete tutorial, be sure to read through the Template Syntax guide.
    In IPS4, logic checks are done using the special {{if}}, {{else}} and {{elseif}} tags. As with standard programming logic, if the expression results in true, the block of code within is executed. If it is false, it isn't (and if there's an else or elseif block, that is tested for a true result instead). So, a block of logic in a template might look like this:
    {{if member.member_id == 3}} <!-- If the member has ID 3, this will be shown --> {{elseif member.member_id == 9}} <!-- But if the member has ID 9, this will be shown instead --> {{else}} <!-- If the member isn't ID 3 or 9, then this will show --> {{endif}} If you need help constructing a logic check, feel free to check out the Customization Resources forum.
     
    Examples. I want to...
    Check if the user is logged in
    {{if member.member_id}} <!-- this will show if the member is logged in --> {{endif}}  
    Check if the user isn't logged in
    {{if !member.member_id}} <!-- this will show if the user is a guest --> {{endif}}  
    Check if the user's ID is one of x, y or z
    You can check as many values as you like; just add more numbers to the array.
    {{if in_array( member.member_id, array( 5, 28, 472 ) )}} <!-- Shows if the member's ID is 5, 28 or 472 --> {{endif}}  
    Check if the user is in group x
    Where x is the group ID number. Note that this also checks secondary member groups.
    {{if member.inGroup('x')}} <!-- Shows if member is in group 'x' --> {{endif}}  
    Check if the user has more than x posts
    In IPS4, all content in all apps counts as a 'post'.
    {{if member.member_posts > 3}} <!-- Shows if the member has more than 3 posts --> {{endif}}  
    Check if the user has fewer than x posts
    In IPS4, all content in all apps counts as a 'post'.
    {{if member.member_posts < 3}} <!-- Shows if the member has fewer than 3 posts --> {{endif}}  
    Check if the user is an administrator
    Note that this also checks if any of the user's secondary member groups has admin permissions.
    {{if member.isAdmin()}} <!-- Shows if the user is an administrator --> {{endif}}  
    Check if the user is banned
    {{if member.isBanned()}} <!-- Shows if the user is banned --> {{endif}}  
    Check if the current page is part of app x
    You need to check the application key. Most are obvious (e.g. forums is the forums app), but there are some others to be aware of. For custom/third-party apps, ask the author which app key they use.
    core = Any system page that isn't part of another app, e.g. search, login/registration, profiles etc. cms = Pages nexus = Commerce {{if request.app == 'forums'}} <!-- Shows if the user is viewing any page in the 'forums' app --> {{endif}}  
    Check if a system setting has value x
    You can check whether system settings have a given value, although you will need to know the setting key used by the backend. Values may not be simple to check, depending on their type - consult our Customization Resources forum if you aren't sure how to check a particular setting.
    {{if settings.auto_polling_enabled}} <!-- Shows if the 'auto_polling_enabled' setting is true (i.e. enabled) --> {{endif}}  
    Check a variable in a template has value x
    Template bits in IPS4 may receive one or more variables from the backend code. You can check the values of these within the template to do something based on the value. This only works within the template into which the variable you are checking is passed - they are not inherited.
    {{if $myVariable == 'some_value'}} <!-- Shows if $myVariable is equal to 'some_value' --> {{endif}}  
    Check if the current forum is forum ID x
    Within the forums app, you can check whether the current page is showing the forum with ID x
    {{if request.app == 'forums' && request.module == 'forums' && request.id == 3}} <!-- Shows if the user is in the forums app, viewing a forum with the ID 3 --> {{endif}} .
  3. Like
    Rikki got a reaction from Night Wolf for a guide, Common logic checks using HTML Logic   
    HTML Logic is a very powerful way of conditionally showing different elements in your theme, depending on the values of certain properties. Since the entire IPS4 framework is available within a logic expression, there's a lot of scope for using different kinds of data to determine what should show.
    In this guide we'll provide a range of examples of common logic checks you might want to do. Even if the exact expression you need isn't listed here, it should provide a good starting point to help you write your own expressions.
     
    Logic Recap
    Let's quickly recap how HTML Logic works. For a more complete tutorial, be sure to read through the Template Syntax guide.
    In IPS4, logic checks are done using the special {{if}}, {{else}} and {{elseif}} tags. As with standard programming logic, if the expression results in true, the block of code within is executed. If it is false, it isn't (and if there's an else or elseif block, that is tested for a true result instead). So, a block of logic in a template might look like this:
    {{if member.member_id == 3}} <!-- If the member has ID 3, this will be shown --> {{elseif member.member_id == 9}} <!-- But if the member has ID 9, this will be shown instead --> {{else}} <!-- If the member isn't ID 3 or 9, then this will show --> {{endif}} If you need help constructing a logic check, feel free to check out the Customization Resources forum.
     
    Examples. I want to...
    Check if the user is logged in
    {{if member.member_id}} <!-- this will show if the member is logged in --> {{endif}}  
    Check if the user isn't logged in
    {{if !member.member_id}} <!-- this will show if the user is a guest --> {{endif}}  
    Check if the user's ID is one of x, y or z
    You can check as many values as you like; just add more numbers to the array.
    {{if in_array( member.member_id, array( 5, 28, 472 ) )}} <!-- Shows if the member's ID is 5, 28 or 472 --> {{endif}}  
    Check if the user is in group x
    Where x is the group ID number. Note that this also checks secondary member groups.
    {{if member.inGroup('x')}} <!-- Shows if member is in group 'x' --> {{endif}}  
    Check if the user has more than x posts
    In IPS4, all content in all apps counts as a 'post'.
    {{if member.member_posts > 3}} <!-- Shows if the member has more than 3 posts --> {{endif}}  
    Check if the user has fewer than x posts
    In IPS4, all content in all apps counts as a 'post'.
    {{if member.member_posts < 3}} <!-- Shows if the member has fewer than 3 posts --> {{endif}}  
    Check if the user is an administrator
    Note that this also checks if any of the user's secondary member groups has admin permissions.
    {{if member.isAdmin()}} <!-- Shows if the user is an administrator --> {{endif}}  
    Check if the user is banned
    {{if member.isBanned()}} <!-- Shows if the user is banned --> {{endif}}  
    Check if the current page is part of app x
    You need to check the application key. Most are obvious (e.g. forums is the forums app), but there are some others to be aware of. For custom/third-party apps, ask the author which app key they use.
    core = Any system page that isn't part of another app, e.g. search, login/registration, profiles etc. cms = Pages nexus = Commerce {{if request.app == 'forums'}} <!-- Shows if the user is viewing any page in the 'forums' app --> {{endif}}  
    Check if a system setting has value x
    You can check whether system settings have a given value, although you will need to know the setting key used by the backend. Values may not be simple to check, depending on their type - consult our Customization Resources forum if you aren't sure how to check a particular setting.
    {{if settings.auto_polling_enabled}} <!-- Shows if the 'auto_polling_enabled' setting is true (i.e. enabled) --> {{endif}}  
    Check a variable in a template has value x
    Template bits in IPS4 may receive one or more variables from the backend code. You can check the values of these within the template to do something based on the value. This only works within the template into which the variable you are checking is passed - they are not inherited.
    {{if $myVariable == 'some_value'}} <!-- Shows if $myVariable is equal to 'some_value' --> {{endif}}  
    Check if the current forum is forum ID x
    Within the forums app, you can check whether the current page is showing the forum with ID x
    {{if request.app == 'forums' && request.module == 'forums' && request.id == 3}} <!-- Shows if the user is in the forums app, viewing a forum with the ID 3 --> {{endif}} .
  4. Like
    Rikki got a reaction from Eupolemos for a guide, Responsiveness   
    Introduction to responsive classes
    IPS4's CSS framework is responsive, meaning elements adapt according to the size of the display the users chooses to use. In most cases, the existing classes already outlined in this guide take care of it for you; for example, menus automatically adjust, and tab bars collapse into a dropdown menu on mobile phones.
    There may be times when you need to control on which devices sizes elements show or hide themselves. For example, if you add a custom footer element, you may want to only show it on desktop, and hide it from tablets or phones.
    The responsive classes that IPS4 provides allow you to control this kind of behavior.
     
    Responsive sizes used by IPS4
    For the purposes of the media queries we use to control responsiveness, the following sizes represent each device:
    Phones - up to 767 pixels wide Tablets - between 768 pixels and 979 pixels wide Desktops - 980 pixels and wider  
    Basic show/hide functionality
    The CSS framework includes two groups of three classes that show or hide elements on desktop, tablet and phone-sized devices, respectively. The classes act in an exclusive way; that is, if you use the show classes, any devices that don't match will not show the element. The opposite is also true; if you use the hide classes, then the element will not show on those devices but will show on the others not specified.
    The classes are:
    ipsResponsive_hidePhone ipsResponsive_hideTablet ipsResponsive_hideDesktop ipsResponsive_showPhone ipsResponsive_showTablet ipsResponsive_showDesktop You can combine these as needed. For example:
    <div class='ipsResponsive_hidePhone ipsResponsive_hideTablet'> This element *will not* display on phones or tablets, but *will* display on desktops </div>  
    Additional classes to control element display
    When using the show classes outlined above, you typically need to include an additional class that controls how the element is rendered. This can be one of the following:
    ipsResponsive_block ipsResponsive_inlineBlock ipsResponsive_inline <div class='ipsResponsive_showDesktop ipsResponsive_block'> This element will *only* show on desktop sizes, and will render as a block-level element. </div> These additional classes aren't usually necessary when using the hide classes.
  5. 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
  6. 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
  7. Like
    Rikki got a reaction from BomAle for a guide, Mixins   
    Mixins are a special type of controller that allow you to augment or change the functionality of an existing controller. This is particularly useful when you need to change something about how a built-in controller works.
     
    Basic structure
    This is the boilerplate for a mixin:
    ;( function($, _, undefined){ "use strict"; ips.controller.mixin('mixinName', 'core.global.core.table', true, function () { // Your code goes here }); }(jQuery, _)); The method signature is:
    ips.controller.mixin( string mixinName, string extendsController, boolean autoLoad, function mixinBody ) mixinName
    A name that will refer to this mixin extendsController
    The full name of the controller that this mixin will extend (e.g. core.global.core.table) autoLoad
    Boolean indicating whether this mixin should always extend the extendsController controller, or only when specified mixinBody
    A function that returns the behaviors that the mixin defines  
    How a mixin works
    A mixin works by allowing you to provide custom code that will execute at key points when the parent controller's method is called. To do that, there are three important methods available to a mixin:
    before()
    Run the specified code before the parent controller's method after()
    Run the specified code after the parent controller's method around()
    The specified code is passed a reference to the parent controller's method, allowing it to be called when desired (and the return value modified In addition to hooking into existing controller methods, your mixin can also provide new methods for its own use and, notably, simply redefine a method present in the parent controller in order to completely replace its functionality.
     
    A note about this
    Within the mixin body, you'll be adding methods to this. The mixin executes in the same context as the parent controller; that is, this in a mixin refers to both the mixin and the controller it extends, allowing you to call methods from the controller, and any create yourself in the mixin. During execution, they are one and the same.
    The same is also true within methods in your mixin since, like in controllers, methods are automatically bound to the controller for you. You may be familiar with this.scope in controller methods (which refers to the DOM element onto which the controller is applied). Since mixin methods are bound in exactly the same way, using this.scope in a mixin method will still give you the element onto which the controller is applied.
     
    before() and after()
    The behavior of these two methods are very similar. They simply allow you to execute your custom code either immediately before, or immediately after the parent controller's code. Your custom code receives the parameters that are passed into the parent method, but not the return value (if any).
    A common usage of either method is to add additional event handlers to a controller. A controller sets up its event handlers in the initialize method, and so a mixin can add more handlers like so:
    this.before('initialize', function () { this.on('click', '#button', this._doSomething); this.on('click', '#button2', this._doSomethingElse); }); In this case, our function will be executed, and then the parent's own initialize method will be executed.
    In this example we don't deal with any parameters but, if the parent method is called with any, they will also be available to your mixin function as normal parameters, in the same order.
     
    around()
    This behaves differently to the previous example, because rather than simply being executed before or after the parent, it actually provides the parent method as a reference to your own function. This allows you to call the parent method at a time of your choosing - perhaps determined based on some logic in your code. Since you have control over calling the parent method, you also have access to its return value, meaning that around can also be used as a way to modify the value that is returned from a controller method.
    As an example, let's assume that the parent controller method returns a JSON object, but we want to augment this with some additional key/values. We can do this using the around call, like so:
    this.around('parentMethod', function (origFn) { var returned = origFn(); return _.extend( returned, { key1: true, key2: false }); }); Notice that the parent method is passed in as a parameter (if the method has any other parameters, these will appear first, and the parent method will be the last parameter). We call this method in order to get its return value for our own use. When we look at the parent method we know that it returns a JSON object, so we extend it with our own values.
    It's worth noting that since you receive both the original parameters, and a reference to the parent method, you have the ability to modify the parameter values before passing them into the parent method. This approach can offer a lot of flexibility.
     
    Custom methods and replacing existing methods
    Finally, you can create new methods in your mixin, or completely replace methods from the parent controller by redefining them. In both cases, this is done like so:
    this.myMethod = function () { //... }; Of course, if you replace an existing method, be sure it plays nicely with any calls to it!
     
    Calling a mixin
    Mixins can be applied to controllers manually when needed (you don't need to do this if you configured your mixing to automatically apply to the controller, though). To do so, specify the mixin name in parenthesis after the controller. For example:
    <div data-controller='core.front.core.someController( mixinName )'> </div> Multiple mixins can be provided if they are comma-delimited.
    Note that mixin files are not loaded on demand in the same way that controller files may be (but they will be compiled into bundles in the same way at build-time). In order for a mixin to be applied, it must be included in the page output. This means that if you're creating a plugin that (for example) has a mixin that applies to a core controller, you are responsible for ensuring the mixin file is included in the page as needed. This may mean creating a theme hook that modifies the output of the includeJS template.
  8. 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
  9. 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)
     
  10. Like
    Rikki got a reaction from lferezy4 for a guide, Buttons   
    Basics
    The button classes described here can be applied to any element, although typically would be applied to an element like a, input[type="submit"] or button so that the user can interact with it.
    As a minimum, a button should receive the basic ipsButton class, plus a size class and a style class (explained below).
     
    Button styles
    ipsButton_normal
    Normal button ipsButton_primary
    Primary button ipsButton_alternate
    Alternate button ipsButton_important
    Important button ipsButton_light
    Light button ipsButton_veryLight
    Very light button ipsButton_overlaid
    Overlaid button ipsButton_link
    Link button  
    Button sizes
    ipsButton_medium
    Medium button ipsButton_verySmall
    Very small button ipsButton_small
    Small button ipsButton_large
    Large button ipsButton_veryLarge
    Very large button ipsButton_fullWidth
    Can be combined with another size, above.
    Full width button  
    Disabled buttons
    Buttons can be visually disabled either by adding the class ipsButton_disabled, or, on relevant input elements, adding the disabled property. For example:
    <a href='#' class='ipsButton ipsButton_normal ipsButton_medium ipsButton_disabled'>Disabled button (link)</a> <input type='submit' class='ipsButton ipsButton_normal ipsButton_medium' disabled value='Disabled button (input)'> These would render like so:
    Disabled button (link)  
    Split buttons
    Split buttons allow you to create toolbars easily by specifying a list of buttons that display joined to each other.
    They are created by specifying the class ipsButton_split on a wrapper element containing two or more buttons. The wrapper element can be a <ul> tag, or any other that makes sense for your use.
    All of the buttons in a split button group should be the same size, otherwise results are unpredictable. Different styles can be used on each button, though.
    <ul class='ipsButton_split'> <li><a href='#' class='ipsButton ipsButton_small ipsButton_primary'>Button 1</a></li> <li><a href='#' class='ipsButton ipsButton_small ipsButton_light'>Button 2</a></li> <li><a href='#' class='ipsButton ipsButton_small ipsButton_light'>Button 3</a></li> </ul> Button 1 Button 2 Button 3  
  11. Like
    Rikki got a reaction from Ambiences for a guide, Using designer's mode   
    While the standard template editor is useful for light template editing, for larger, more complex changes, editing with a real IDE is desirable. The IPS Community Suite facilitates this through something called Designer's Mode.
     
    What is Designer's Mode?
    Designer's Mode allows you to use a real IDE by exporting all of the templates and CSS files to disk as files, and then reimporting them to the suite when you have finished editing them.
    With Designer's Mode enabled, the software will load its theme from this folder, meaning you can edit the files and see the changes as you make them.
    Warning Designer's Mode should not be used on a live community because it will have resource usage implications. We always recommend developing themes with Designer's Mode on a test/development installation.  
    Enabling Designer's Mode
    The first step is to create a folder called themes in your root community directory (that is, the same place your conf_global.php exists). CHMOD this folder to 777 to enable the suite to write the files.
    Next, navigate to Customization -> Themes in the AdminCP. In the toolbar at the top of the page, click the Designer's Mode button. Toggle the setting on after reading the information box, and then save the form. IPS4 will begin writing the theme files to disk.
    Once complete, you will see a directory structure similar to this in the /themes folder on your server:

    All themes currently installed are exported when Designer's Mode is enabled; the parent folders in this structure are named based on the theme ID. You can cross-reference the theme ID you wish to edit on the theme listing page in the AdminCP while Designer's Mode is enabled:

    Each theme folder contains four key parts:
    /css
    The CSS for the theme, grouped first by app, then by location (front/admin/global). /html
    The *.phtml HTML templates this theme uses, grouped first by app, then by location (front/admin/global) then by section. lang.php
    A language file into which you can insert any custom language strings your theme requires. They should be in this format: 'my_language_key' => "The English phrase"  
    /resources
    Resources for the theme (primarily images), grouped first by app, then by location (front/admin/global) then by type.
    Resources aren't allowed to be larger than 1.5 MB . 
     
    Editing templates
    When you edit the *.phtml template files exporting by Designer's Mode, you will notice a special tag on the first line of each file that looks like this:
    <ips:template parameters="$title,$html,$location=array()" /> This tag is how the software knows which variables belong to this template. It is very important that you do not modify this line in template files, or your theme may break.
     
    Completing Designer's Mode
    When you are happy with your changes, you can disable Designer's Mode to import them back into the suite (note that you can enable Designer's Mode again later to continue).
    To do this, go back to the theme listing screen at Customization -> Themes, and click the red Designer's Mode Enabled button. When you toggle the setting off, you will see additional settings asking you to confirm that you want to synchronize the changes.
    Warning Be sure the Synchronize option is enabled when you save this form, otherwise your changes will be lost.
    You can select individual themes to sync, or all of them. You can also choose whether to keep the files on disk or automatically delete them once the sync is done.
  12. 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  
  13. Like
    Rikki got a reaction from sobrenome for a guide, Data Lists   
    Description
    The data list CSS module allows us to display complex lists, while rearranging the display in situations that demand it, such as on small devices.
     
    Usage
    A data list consists of a wrapper and individual list items, which can contain various types of data. In most cases, a data list would use one of the HTML list elements (such as ul or ol) for semantic purposes, though this isn't necessarily required.
    The basic markup structure is as follows:
    <ol class='ipsDataList' itemscope itemtype="http://schema.org/ItemList"> <meta itemprop="itemListOrder" content="Descending"> <li class='ipsDataItem ipsDataItem_unread' itemprop="itemListElement"> ... </li> <li class='ipsDataItem' itemprop="itemListElement"> ... </li> <li class='ipsDataItem' itemprop="itemListElement"> ... </li> </ol> The root element should be given the classname ipsDataList. Individual list items receive the classname ipsDataItem. To indicate unread status within a row, add the class ipsDataItem_unread to the list item. The other elements in the row may style differently in 'unread' rows to indicate that status.
    Within the ipsDataItem, multiple other elements can exist which (at desktop resolution) represent cells of data. On smaller devices, these elements reflow to give a more suitable layout. These elements are outlined below. An example of a data list row showing many of these options is shown here:
    Pre-sales questions
    Question before you purchase? Post here and get help from both IPS and from other clients. You can also email sales@invisionpower.com for assistance.
    Company Feedback General Suite Feedback 18,852 Posts BBCode’s description variable By admin Yesterday  
    Row Spacing
    By default, rows are comfortably spaced. An additional class ipsDataList_reducedSpacing is available where reduced horizontal cell padding is desired.
     
    Zebra Striping
    By default, zebra striping (alternate background colors) are not included on data lists. To add them, add the class ipsDataList_zebra to the data list wrapper.
     
    Main content cell - ipsDataItem_main
    Represents the primary data in the row, typically containing the row title and some metadata. Expands to take up whatever space is left by the remaining cells in the row. Example:
    <div class='ipsDataItem_main'> <h4 class='ipsDataItem_title'><a href='#'>Item title</a></h4> <p class='ipsDataItem_meta'> By testadmin, yesterday, 2:21pm </p> </div> Within this cell, ipsDataItem_title defines the title element, while ipsDataItem_meta defines some non-specific metadata associated with the title.
    In the main cell, a sub-list can be specified for data such as sub-forums or sub-albums. This should appear after the ipsDataItem_meta element. An example of the markup:
    <ul class='<strong>ipsDataItem_subList</strong> ipsList_inline'> <li><a href='#'>Sub-item 1</a></li> <li class='ipsDataItem_unread'><a href='#'>Sub-item 2</a></li> </ul>  
    Statistics cell - ipsDataItem_stats
    This class is applied to an element which represents statistics for this row, such as the number of replies in a topic or the number of downloads a file has. An example of its usage:
    <dl class='ipsDataItem_stats'> <dt class='ipsDataItem_stats_number'>18,852</dt> <dd class='ipsDataItem_stats_type'>Posts</dd> </dl> The data within this element is marked up with two additional classes:
    ipsDataItem_stats_number - represents the actual statistical value ipsDataItem_stats_type - represents the type of data The additional class ipsDataItem_statsLarge can be added to the element where the statistic is particularly important. This significantly increases the font size of the value to help it stand out.
     
    Last poster cell - ipsDataItem_lastPoster
    Used to represent the 'last poster' information, such as in a topic or other record. An example of its use:
    <ul class='<strong>ipsDataItem_lastPoster ipsDataItem_withPhoto</strong>'> <li><img src='images/photo.jpeg'></li> <li><a href='#'>Username</a></li> <li><time data-short='1 dy'>Time stamp</time></li> </ul> Within this element are two or three more elements. If the ipsDataItem_withPhoto class is used, the first element should contain a user photo, otherwise, the first element can be omitted. The second element typically will contain the username, while the last will contain the time information.
    The last element contains a time element with a data-short attribute. This attibute should contain a very short representation of the date/time, and it is used on small devices. The PHP framework generates these for you.
     
    Generic cells
    A number of generic cell sizes are available for custom types of data. The cell should contain the class ipsDataItem_generic and one of the following classes:
    ipsDataItem_size1 - 50px ipsDataItem_size2 - 75px ipsDataItem_size3 - 100px ipsDataItem_size4 - 125px ipsDataItem_size5 - 150px ipsDataItem_size6 - 175px ipsDataItem_size7 - 200px ipsDataItem_size8 - 225px ipsDataItem_size9 - 250px  
    Other cell types
    In addition to the main cell types above, there are additional cell classes that can be used.
    ipsDataItem_icon - A column which contains a status icon for the row, such as a forum icon ipsDataItem_modCheck - A narrow column that should hold a moderator checkbox to select the row  
    Coloring rows
    Four additional classes are available to optionally add a background color to the row to denote status:
    ipsDataItem_new - New items ipsDataItem_warning - Items showing a warning state ipsDataItem_error  - Items with an error ipsDataItem_info - An informational state  
    Putting it together
    Here is the code for the example shown at the top of the page:
    <ol class='ipsDataList'> <li class='ipsDataItem ipsClearfix ipsDataItem_unread'> <div class='ipsDataItem_main'> <h4 class='ipsDataItem_title'><a href='#'>Pre-sales questions</a></h4> <p class='ipsDataItem_meta'> Question before you purchase? Post here and get help from both IPS and from other clients. You can also email sales@invisionpower.com for assistance. </p> <ul class='ipsDataItem_subList ipsList_inline'> <li><a href='#'>Company Feedback</a></li> <li class='ipsDataItem_unread'><a href='#'>General Suite Feedback</a></li> </ul> </div> <dl class='ipsDataItem_stats ipsDataItem_statsLarge'> <dt class='ipsDataItem_stats_number'>18,852</dt> <dd class='ipsDataItem_stats_type ipsType_light'>Posts</dd> </dl> <ul class='ipsDataItem_lastPoster ipsDataItem_withPhoto'> <li><a href='#' class='ipsUserPhoto ipsUserPhoto_mini ipsPos_left'><img src='image.jpg' alt=''></a></li> <li><a href='#'>BBCode’s description variable</a></li> <li>By <a href='#'>admin</a></li> <li><time class='ipsType_light' data-short='1 dy'>Yesterday</time></li> </ul> <div class='ipsDataItem_modCheck'> <input type='checkbox' checked> </div> </li> </ol>  
  14. 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.
  15. Like
    Rikki got a reaction from sobrenome for a guide, Common logic checks using HTML Logic   
    HTML Logic is a very powerful way of conditionally showing different elements in your theme, depending on the values of certain properties. Since the entire IPS4 framework is available within a logic expression, there's a lot of scope for using different kinds of data to determine what should show.
    In this guide we'll provide a range of examples of common logic checks you might want to do. Even if the exact expression you need isn't listed here, it should provide a good starting point to help you write your own expressions.
     
    Logic Recap
    Let's quickly recap how HTML Logic works. For a more complete tutorial, be sure to read through the Template Syntax guide.
    In IPS4, logic checks are done using the special {{if}}, {{else}} and {{elseif}} tags. As with standard programming logic, if the expression results in true, the block of code within is executed. If it is false, it isn't (and if there's an else or elseif block, that is tested for a true result instead). So, a block of logic in a template might look like this:
    {{if member.member_id == 3}} <!-- If the member has ID 3, this will be shown --> {{elseif member.member_id == 9}} <!-- But if the member has ID 9, this will be shown instead --> {{else}} <!-- If the member isn't ID 3 or 9, then this will show --> {{endif}} If you need help constructing a logic check, feel free to check out the Customization Resources forum.
     
    Examples. I want to...
    Check if the user is logged in
    {{if member.member_id}} <!-- this will show if the member is logged in --> {{endif}}  
    Check if the user isn't logged in
    {{if !member.member_id}} <!-- this will show if the user is a guest --> {{endif}}  
    Check if the user's ID is one of x, y or z
    You can check as many values as you like; just add more numbers to the array.
    {{if in_array( member.member_id, array( 5, 28, 472 ) )}} <!-- Shows if the member's ID is 5, 28 or 472 --> {{endif}}  
    Check if the user is in group x
    Where x is the group ID number. Note that this also checks secondary member groups.
    {{if member.inGroup('x')}} <!-- Shows if member is in group 'x' --> {{endif}}  
    Check if the user has more than x posts
    In IPS4, all content in all apps counts as a 'post'.
    {{if member.member_posts > 3}} <!-- Shows if the member has more than 3 posts --> {{endif}}  
    Check if the user has fewer than x posts
    In IPS4, all content in all apps counts as a 'post'.
    {{if member.member_posts < 3}} <!-- Shows if the member has fewer than 3 posts --> {{endif}}  
    Check if the user is an administrator
    Note that this also checks if any of the user's secondary member groups has admin permissions.
    {{if member.isAdmin()}} <!-- Shows if the user is an administrator --> {{endif}}  
    Check if the user is banned
    {{if member.isBanned()}} <!-- Shows if the user is banned --> {{endif}}  
    Check if the current page is part of app x
    You need to check the application key. Most are obvious (e.g. forums is the forums app), but there are some others to be aware of. For custom/third-party apps, ask the author which app key they use.
    core = Any system page that isn't part of another app, e.g. search, login/registration, profiles etc. cms = Pages nexus = Commerce {{if request.app == 'forums'}} <!-- Shows if the user is viewing any page in the 'forums' app --> {{endif}}  
    Check if a system setting has value x
    You can check whether system settings have a given value, although you will need to know the setting key used by the backend. Values may not be simple to check, depending on their type - consult our Customization Resources forum if you aren't sure how to check a particular setting.
    {{if settings.auto_polling_enabled}} <!-- Shows if the 'auto_polling_enabled' setting is true (i.e. enabled) --> {{endif}}  
    Check a variable in a template has value x
    Template bits in IPS4 may receive one or more variables from the backend code. You can check the values of these within the template to do something based on the value. This only works within the template into which the variable you are checking is passed - they are not inherited.
    {{if $myVariable == 'some_value'}} <!-- Shows if $myVariable is equal to 'some_value' --> {{endif}}  
    Check if the current forum is forum ID x
    Within the forums app, you can check whether the current page is showing the forum with ID x
    {{if request.app == 'forums' && request.module == 'forums' && request.id == 3}} <!-- Shows if the user is in the forums app, viewing a forum with the ID 3 --> {{endif}} .
  16. Like
    Rikki got a reaction from sobrenome for a guide, Field formatting   
    By default, Pages will show your custom fields as badges in the listing and record views, and when creating a field you can choose a color and some basic positioning options. For many of your uses, this may be sufficient, but for more advanced usage Pages allows you to set up custom field formatters that take the raw data and display it however you wish. We're going to use field formatters for each of our custom fields so we can control exactly how they look.
     
    How do field formatters work?
    Field formatters expose both the raw and formatted field data to you, enabling you to write your own HTML to generate the output of the field. They can be simple, as most of ours will be, or as complex as you need.
    The listing and record views can each have a different formatting, which will be useful in many cases (although for the way we display our Release Notes, we won't be using the display versions).
     
    What data is available in a formatter?
    Field formats make the following variables available: 
    $label
    Contains the field label, which is the name you entered for the field (e.g. "Release date") $value
    Contains the processed field value. For example, if you have a select field, this variable contains the text of the value, not the key. $formValue
    In contrast to the above, this contains the raw form value. For select fields it will be the key, for Yes/No fields it will be a simple boolean value, etc. In situations where HTML is in a value, you may need to append |raw to the variable to have it correctly parsed.
    Warning Be very careful using the |raw output method. By bypassing escaping of HTML characters, you can open your site to security problems when displaying user-generated content.
     
    Formatting the security release field
    We're going to add a custom formatter for our Security Release field, which if you recall shows a red warning triangle when we set the field to Yes.
    To start, head over to the field listing page for our database, and click the edit icon next to the Security Release field. On the Display tab, we want to change the Listing View Format to Custom. This will show an editor where we'll enter our HTML. This is the HTML we will use:
    {{if $formValue == "1"}}<span class='ipsType_large ipsType_negative ipsPos_right cRelease_security' data-ipsTooltip title='This is a security release'><i class='fa fa-warning'></i></span>{{endif}} Let's review what is happening here. The opening HTML logic {{if $formValue == "1"}} is simply checking the value of the field. Since this is a Yes/No field, the raw form value is either 1 or 0. We only want to show the security release icon when this field is set to Yes, so if the form value is 0, it simply skips over this logic and shows nothing. Inside the {{if}} we have some simple HTML that shows a red triangle icon (see our CSS framework guides for information on the classnames). We've also added a custom classname cRelease_security that we'll use when we create our own custom CSS later
     
    Formatting the release date field
    Another field we'll format is the Release Date field. This field shows a date if set, or "In Development" if no date has been set. As before, set the Listing View Format to Custom, and use this HTML:
    {{if $formValue}}Released {$value}{{else}}<span class='ipsType_light'><em>In Development</em></span>{{endif}} What we're doing here is checking if there's any form value - if there is, we know a date has been chosen, and we display the processed version contained in $value. If there isn't, then after the {{else}} we show the "In Development" text inside a span.
     
    Other fields
    Here's the HTML for the other fields:
    Current Release
    {{if $formValue == 1}}<span class='ipsBadge ipsBadge_positive' data-ipsTooltip title='This is the most current available release'>Current Release</span>{{endif}} Beta Release
    {{if $formValue == 1}}<span class='ipsBadge ipsBadge_negative' data-ipsTooltip title='A beta is available for this version'>Beta</span>{{endif}} Additional Information
    This field is set to 'No formatting' for the Display template.
     
    With our custom fields set up and formatted correctly, we can move on to templates.
    Adding sample data & Adjusting sorting Creating custom fields
  17. Like
    Rikki got a reaction from sobrenome for a guide, Layout: Grids   
    Description
    The grid module provides classes for building layouts based on a flexible 12-column grid, with automatic margins, and with additional classes to enable the layout to collapse properly on smaller devices.
     
    Usage
    A grid should be made up of a wrapper element with the class ipsGrid, and direct descendants with appropriate size classes applied (see below). For example:
    <div class='ipsGrid'> <div class='ipsGrid_span3'>Span 3</div> <div class='ipsGrid_span3'>Span 3</div> <div class='ipsGrid_span4'>Span 4</div> <div class='ipsGrid_span2'>Span 2</div> </div> This would render as:
    Span 3 Span 3 Span 4 Span 2 Grid classes ipsGrid_span1 through ipsGrid_span12 are available for the various column sizes.
     
    Wrapping Grid Items
    Elements in a grid will automatically neatly wrap to new rows, providing every item in the grid uses the same span width and height, without you needing to manually create new row structures. For example:
    <div class='ipsGrid'> <div class='ipsGrid_span6'>Span 6</div> <div class='ipsGrid_span6'>Span 6</div> <div class='ipsGrid_span6'>Span 6</div> <div class='ipsGrid_span6'>Span 6</div> </div> Span 6 Span 6 Span 6 Span 6 For grids where your items may differ in height or width, consider the ips.ui.grid widget instead.
     
    Responsiveness
    To cause the grid layout to collapse on smaller devices, add either ipsGrid_collapseTablet or ipsGrid_collapsePhone to the class list on the wrapper element, like so:
    <div class='ipsGrid ipsGrid_collapsePhone'> ... </div>  
  18. Like
    Rikki got a reaction from sobrenome for a guide, Buttons   
    Basics
    The button classes described here can be applied to any element, although typically would be applied to an element like a, input[type="submit"] or button so that the user can interact with it.
    As a minimum, a button should receive the basic ipsButton class, plus a size class and a style class (explained below).
     
    Button styles
    ipsButton_normal
    Normal button ipsButton_primary
    Primary button ipsButton_alternate
    Alternate button ipsButton_important
    Important button ipsButton_light
    Light button ipsButton_veryLight
    Very light button ipsButton_overlaid
    Overlaid button ipsButton_link
    Link button  
    Button sizes
    ipsButton_medium
    Medium button ipsButton_verySmall
    Very small button ipsButton_small
    Small button ipsButton_large
    Large button ipsButton_veryLarge
    Very large button ipsButton_fullWidth
    Can be combined with another size, above.
    Full width button  
    Disabled buttons
    Buttons can be visually disabled either by adding the class ipsButton_disabled, or, on relevant input elements, adding the disabled property. For example:
    <a href='#' class='ipsButton ipsButton_normal ipsButton_medium ipsButton_disabled'>Disabled button (link)</a> <input type='submit' class='ipsButton ipsButton_normal ipsButton_medium' disabled value='Disabled button (input)'> These would render like so:
    Disabled button (link)  
    Split buttons
    Split buttons allow you to create toolbars easily by specifying a list of buttons that display joined to each other.
    They are created by specifying the class ipsButton_split on a wrapper element containing two or more buttons. The wrapper element can be a <ul> tag, or any other that makes sense for your use.
    All of the buttons in a split button group should be the same size, otherwise results are unpredictable. Different styles can be used on each button, though.
    <ul class='ipsButton_split'> <li><a href='#' class='ipsButton ipsButton_small ipsButton_primary'>Button 1</a></li> <li><a href='#' class='ipsButton ipsButton_small ipsButton_light'>Button 2</a></li> <li><a href='#' class='ipsButton ipsButton_small ipsButton_light'>Button 3</a></li> </ul> Button 1 Button 2 Button 3  
  19. Like
    Rikki got a reaction from Meddysong for a guide, Common logic checks using HTML Logic   
    HTML Logic is a very powerful way of conditionally showing different elements in your theme, depending on the values of certain properties. Since the entire IPS4 framework is available within a logic expression, there's a lot of scope for using different kinds of data to determine what should show.
    In this guide we'll provide a range of examples of common logic checks you might want to do. Even if the exact expression you need isn't listed here, it should provide a good starting point to help you write your own expressions.
     
    Logic Recap
    Let's quickly recap how HTML Logic works. For a more complete tutorial, be sure to read through the Template Syntax guide.
    In IPS4, logic checks are done using the special {{if}}, {{else}} and {{elseif}} tags. As with standard programming logic, if the expression results in true, the block of code within is executed. If it is false, it isn't (and if there's an else or elseif block, that is tested for a true result instead). So, a block of logic in a template might look like this:
    {{if member.member_id == 3}} <!-- If the member has ID 3, this will be shown --> {{elseif member.member_id == 9}} <!-- But if the member has ID 9, this will be shown instead --> {{else}} <!-- If the member isn't ID 3 or 9, then this will show --> {{endif}} If you need help constructing a logic check, feel free to check out the Customization Resources forum.
     
    Examples. I want to...
    Check if the user is logged in
    {{if member.member_id}} <!-- this will show if the member is logged in --> {{endif}}  
    Check if the user isn't logged in
    {{if !member.member_id}} <!-- this will show if the user is a guest --> {{endif}}  
    Check if the user's ID is one of x, y or z
    You can check as many values as you like; just add more numbers to the array.
    {{if in_array( member.member_id, array( 5, 28, 472 ) )}} <!-- Shows if the member's ID is 5, 28 or 472 --> {{endif}}  
    Check if the user is in group x
    Where x is the group ID number. Note that this also checks secondary member groups.
    {{if member.inGroup('x')}} <!-- Shows if member is in group 'x' --> {{endif}}  
    Check if the user has more than x posts
    In IPS4, all content in all apps counts as a 'post'.
    {{if member.member_posts > 3}} <!-- Shows if the member has more than 3 posts --> {{endif}}  
    Check if the user has fewer than x posts
    In IPS4, all content in all apps counts as a 'post'.
    {{if member.member_posts < 3}} <!-- Shows if the member has fewer than 3 posts --> {{endif}}  
    Check if the user is an administrator
    Note that this also checks if any of the user's secondary member groups has admin permissions.
    {{if member.isAdmin()}} <!-- Shows if the user is an administrator --> {{endif}}  
    Check if the user is banned
    {{if member.isBanned()}} <!-- Shows if the user is banned --> {{endif}}  
    Check if the current page is part of app x
    You need to check the application key. Most are obvious (e.g. forums is the forums app), but there are some others to be aware of. For custom/third-party apps, ask the author which app key they use.
    core = Any system page that isn't part of another app, e.g. search, login/registration, profiles etc. cms = Pages nexus = Commerce {{if request.app == 'forums'}} <!-- Shows if the user is viewing any page in the 'forums' app --> {{endif}}  
    Check if a system setting has value x
    You can check whether system settings have a given value, although you will need to know the setting key used by the backend. Values may not be simple to check, depending on their type - consult our Customization Resources forum if you aren't sure how to check a particular setting.
    {{if settings.auto_polling_enabled}} <!-- Shows if the 'auto_polling_enabled' setting is true (i.e. enabled) --> {{endif}}  
    Check a variable in a template has value x
    Template bits in IPS4 may receive one or more variables from the backend code. You can check the values of these within the template to do something based on the value. This only works within the template into which the variable you are checking is passed - they are not inherited.
    {{if $myVariable == 'some_value'}} <!-- Shows if $myVariable is equal to 'some_value' --> {{endif}}  
    Check if the current forum is forum ID x
    Within the forums app, you can check whether the current page is showing the forum with ID x
    {{if request.app == 'forums' && request.module == 'forums' && request.id == 3}} <!-- Shows if the user is in the forums app, viewing a forum with the ID 3 --> {{endif}} .
  20. Like
    Rikki got a reaction from MeMaBlue for a guide, Responsiveness   
    Introduction to responsive classes
    IPS4's CSS framework is responsive, meaning elements adapt according to the size of the display the users chooses to use. In most cases, the existing classes already outlined in this guide take care of it for you; for example, menus automatically adjust, and tab bars collapse into a dropdown menu on mobile phones.
    There may be times when you need to control on which devices sizes elements show or hide themselves. For example, if you add a custom footer element, you may want to only show it on desktop, and hide it from tablets or phones.
    The responsive classes that IPS4 provides allow you to control this kind of behavior.
     
    Responsive sizes used by IPS4
    For the purposes of the media queries we use to control responsiveness, the following sizes represent each device:
    Phones - up to 767 pixels wide Tablets - between 768 pixels and 979 pixels wide Desktops - 980 pixels and wider  
    Basic show/hide functionality
    The CSS framework includes two groups of three classes that show or hide elements on desktop, tablet and phone-sized devices, respectively. The classes act in an exclusive way; that is, if you use the show classes, any devices that don't match will not show the element. The opposite is also true; if you use the hide classes, then the element will not show on those devices but will show on the others not specified.
    The classes are:
    ipsResponsive_hidePhone ipsResponsive_hideTablet ipsResponsive_hideDesktop ipsResponsive_showPhone ipsResponsive_showTablet ipsResponsive_showDesktop You can combine these as needed. For example:
    <div class='ipsResponsive_hidePhone ipsResponsive_hideTablet'> This element *will not* display on phones or tablets, but *will* display on desktops </div>  
    Additional classes to control element display
    When using the show classes outlined above, you typically need to include an additional class that controls how the element is rendered. This can be one of the following:
    ipsResponsive_block ipsResponsive_inlineBlock ipsResponsive_inline <div class='ipsResponsive_showDesktop ipsResponsive_block'> This element will *only* show on desktop sizes, and will render as a block-level element. </div> These additional classes aren't usually necessary when using the hide classes.
  21. Like
    Rikki got a reaction from MeMaBlue for a guide, Exporting a language pack you have created   
    When you are happy with your language pack, you can export it and share it with other people (such as via our Marketplace) or simply keep it as a backup.
    To do so, navigate to Customization -> Languages in the AdminCP, and click the dropdown menu next to the language you want to export. Click on the Download item, and your browser will prompt you to download a file:

     
    The file you download will have the extension .xml, and is the only file you need to distribute to share your language pack.
  22. Like
    Rikki got a reaction from Ilya Hoilik for a guide, Mixins   
    Mixins are a special type of controller that allow you to augment or change the functionality of an existing controller. This is particularly useful when you need to change something about how a built-in controller works.
     
    Basic structure
    This is the boilerplate for a mixin:
    ;( function($, _, undefined){ "use strict"; ips.controller.mixin('mixinName', 'core.global.core.table', true, function () { // Your code goes here }); }(jQuery, _)); The method signature is:
    ips.controller.mixin( string mixinName, string extendsController, boolean autoLoad, function mixinBody ) mixinName
    A name that will refer to this mixin extendsController
    The full name of the controller that this mixin will extend (e.g. core.global.core.table) autoLoad
    Boolean indicating whether this mixin should always extend the extendsController controller, or only when specified mixinBody
    A function that returns the behaviors that the mixin defines  
    How a mixin works
    A mixin works by allowing you to provide custom code that will execute at key points when the parent controller's method is called. To do that, there are three important methods available to a mixin:
    before()
    Run the specified code before the parent controller's method after()
    Run the specified code after the parent controller's method around()
    The specified code is passed a reference to the parent controller's method, allowing it to be called when desired (and the return value modified In addition to hooking into existing controller methods, your mixin can also provide new methods for its own use and, notably, simply redefine a method present in the parent controller in order to completely replace its functionality.
     
    A note about this
    Within the mixin body, you'll be adding methods to this. The mixin executes in the same context as the parent controller; that is, this in a mixin refers to both the mixin and the controller it extends, allowing you to call methods from the controller, and any create yourself in the mixin. During execution, they are one and the same.
    The same is also true within methods in your mixin since, like in controllers, methods are automatically bound to the controller for you. You may be familiar with this.scope in controller methods (which refers to the DOM element onto which the controller is applied). Since mixin methods are bound in exactly the same way, using this.scope in a mixin method will still give you the element onto which the controller is applied.
     
    before() and after()
    The behavior of these two methods are very similar. They simply allow you to execute your custom code either immediately before, or immediately after the parent controller's code. Your custom code receives the parameters that are passed into the parent method, but not the return value (if any).
    A common usage of either method is to add additional event handlers to a controller. A controller sets up its event handlers in the initialize method, and so a mixin can add more handlers like so:
    this.before('initialize', function () { this.on('click', '#button', this._doSomething); this.on('click', '#button2', this._doSomethingElse); }); In this case, our function will be executed, and then the parent's own initialize method will be executed.
    In this example we don't deal with any parameters but, if the parent method is called with any, they will also be available to your mixin function as normal parameters, in the same order.
     
    around()
    This behaves differently to the previous example, because rather than simply being executed before or after the parent, it actually provides the parent method as a reference to your own function. This allows you to call the parent method at a time of your choosing - perhaps determined based on some logic in your code. Since you have control over calling the parent method, you also have access to its return value, meaning that around can also be used as a way to modify the value that is returned from a controller method.
    As an example, let's assume that the parent controller method returns a JSON object, but we want to augment this with some additional key/values. We can do this using the around call, like so:
    this.around('parentMethod', function (origFn) { var returned = origFn(); return _.extend( returned, { key1: true, key2: false }); }); Notice that the parent method is passed in as a parameter (if the method has any other parameters, these will appear first, and the parent method will be the last parameter). We call this method in order to get its return value for our own use. When we look at the parent method we know that it returns a JSON object, so we extend it with our own values.
    It's worth noting that since you receive both the original parameters, and a reference to the parent method, you have the ability to modify the parameter values before passing them into the parent method. This approach can offer a lot of flexibility.
     
    Custom methods and replacing existing methods
    Finally, you can create new methods in your mixin, or completely replace methods from the parent controller by redefining them. In both cases, this is done like so:
    this.myMethod = function () { //... }; Of course, if you replace an existing method, be sure it plays nicely with any calls to it!
     
    Calling a mixin
    Mixins can be applied to controllers manually when needed (you don't need to do this if you configured your mixing to automatically apply to the controller, though). To do so, specify the mixin name in parenthesis after the controller. For example:
    <div data-controller='core.front.core.someController( mixinName )'> </div> Multiple mixins can be provided if they are comma-delimited.
    Note that mixin files are not loaded on demand in the same way that controller files may be (but they will be compiled into bundles in the same way at build-time). In order for a mixin to be applied, it must be included in the page output. This means that if you're creating a plugin that (for example) has a mixin that applies to a core controller, you are responsible for ensuring the mixin file is included in the page as needed. This may mean creating a theme hook that modifies the output of the includeJS template.
  23. 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
  24. Like
    Rikki got a reaction from 60kell for a guide, Typography   
    Description
    The typography module offers a wide range of classes for styling text across the suite
     
    Headings
    A number of heading styles are provided, which can be used for structuring information on the page. They are element-agnostic; you can use them on any of the <h*> tags (or even other tags) - choose the most semantic element for your particular use.
    ipsType_pageTitle
    Most useful as the main title on a page. A larger version is available by also adding the ipsType_largeTitle class.
    This is a page title
     
    ipsType_sectionTitle
    The title of a section on the page.
    This is a section title
     
    ipsType_sectionHead
    A section heading.
    This is a section heading
     
    ipsType_minorHeading
    A small, less-important heading.
    A minor heading
     
    Alignment
    ipsType_left
    Left-aligned text
    ipsType_right
    Right-aligned text
    ipsType_center
    Centered text
     
    Colors
    ipsType_light
    Light text
    ipsType_warning or ipsType_negative
    Warning status text
    ipsType_success
    Success status text
    ipsType_issue
    Issue/intermediate status text
    ipsType_neutral
    Neutral status text
     
    Sizing
    ipsType_small
    Small text
    ipsType_medium
    Medium text
    ipsType_normal
    Normal sizing
    ipsType_large
    Large text
    ipsType_veryLarge
    Very large text
    ipsType_huge (useful for icons)
     
     
    User-generated text/content from CKEditor
    When dealing with content that is generated by users (generally coming from CKEditor), there are three classes that should be used in order to have it display correctly. Generally you will want to use all three although some situations may call for a different treatment. You may also want to apply the classes to different elements - for example, if you have repeating blocks of user content, the ipsContained class might be applied to a wrapper instead of each individual item. When dealing with user-generated content, be sure to test edge cases.
    ipsType_richText
    This is the main class for user-generated content, and enables styles such as responsive images and correct margins.
    ipsType_break
    This ensures words break correctly in user-generated content
    ipsType_contained
    This is a protective measure that ensures content cannot expand out of its given container.
     
    Truncating text
    Text can be truncated on a single line by adding two classes to an element: ipsTruncate ipsTruncate_line. In browsers that support it, this causes overflowing text to be hidden, and instead be replaced by ellipsis.
    Note: This method is designed to work on short pieces of text on a single line, such as text on a button. It does not work effectively on multi-line strings; for those cases you should use the javascript-based ips.ui.truncate widget. It also sets the element to 100% width in order to work; you will need to manually set a width if you wish to overule this behavior.
    This is a long string which won't quite fit on this button  
    Other typography styles
    ipsType_noBreak
    Prevents text from wrapping
    ipsType_reset
    Removes margin (most useful for <h*> and <p> elements)
    ipsType_unbold
    Remove bold styling from text
    ipsType_uppercase
    Makes text uppercase
    ipsType_blendLinks
    When applied to either an element containing links or links themselves, causes the links to match surrounding text styles.
  25. 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  
  26. 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
  27. 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)
     
  28. Like
    Rikki got a reaction from The Biscuit Factory for a guide, Resetting user theme choices   
    On occasion you may wish to override the theme choice members have made (for example, when you install a new default theme). The IPS Community Suite allows you to do this easily on a per-group basis.
    Navigate to Customization -> Themes in the AdminCP, and click the dropdown arrow next to the theme you want to force as the selected theme. Select Set as Members' Theme from the menu:

    In the popup window that will appear, you can choose which groups (or all of them) to reset. For example, if a member in the Members group had chosen the Green Theme to use, by using the Set As Members' Theme and selecting the Members group on the Red Theme, that member's choice will be reset and they'll see the Red Theme in future.
  29. Like
    Rikki got a reaction from MMahdiD25 for a guide, Using designer's mode   
    While the standard template editor is useful for light template editing, for larger, more complex changes, editing with a real IDE is desirable. The IPS Community Suite facilitates this through something called Designer's Mode.
     
    What is Designer's Mode?
    Designer's Mode allows you to use a real IDE by exporting all of the templates and CSS files to disk as files, and then reimporting them to the suite when you have finished editing them.
    With Designer's Mode enabled, the software will load its theme from this folder, meaning you can edit the files and see the changes as you make them.
    Warning Designer's Mode should not be used on a live community because it will have resource usage implications. We always recommend developing themes with Designer's Mode on a test/development installation.  
    Enabling Designer's Mode
    The first step is to create a folder called themes in your root community directory (that is, the same place your conf_global.php exists). CHMOD this folder to 777 to enable the suite to write the files.
    Next, navigate to Customization -> Themes in the AdminCP. In the toolbar at the top of the page, click the Designer's Mode button. Toggle the setting on after reading the information box, and then save the form. IPS4 will begin writing the theme files to disk.
    Once complete, you will see a directory structure similar to this in the /themes folder on your server:

    All themes currently installed are exported when Designer's Mode is enabled; the parent folders in this structure are named based on the theme ID. You can cross-reference the theme ID you wish to edit on the theme listing page in the AdminCP while Designer's Mode is enabled:

    Each theme folder contains four key parts:
    /css
    The CSS for the theme, grouped first by app, then by location (front/admin/global). /html
    The *.phtml HTML templates this theme uses, grouped first by app, then by location (front/admin/global) then by section. lang.php
    A language file into which you can insert any custom language strings your theme requires. They should be in this format: 'my_language_key' => "The English phrase"  
    /resources
    Resources for the theme (primarily images), grouped first by app, then by location (front/admin/global) then by type.
    Resources aren't allowed to be larger than 1.5 MB . 
     
    Editing templates
    When you edit the *.phtml template files exporting by Designer's Mode, you will notice a special tag on the first line of each file that looks like this:
    <ips:template parameters="$title,$html,$location=array()" /> This tag is how the software knows which variables belong to this template. It is very important that you do not modify this line in template files, or your theme may break.
     
    Completing Designer's Mode
    When you are happy with your changes, you can disable Designer's Mode to import them back into the suite (note that you can enable Designer's Mode again later to continue).
    To do this, go back to the theme listing screen at Customization -> Themes, and click the red Designer's Mode Enabled button. When you toggle the setting off, you will see additional settings asking you to confirm that you want to synchronize the changes.
    Warning Be sure the Synchronize option is enabled when you save this form, otherwise your changes will be lost.
    You can select individual themes to sync, or all of them. You can also choose whether to keep the files on disk or automatically delete them once the sync is done.
  30. Like
    Rikki got a reaction from Simon Woods for a guide, Installing a ready-made language pack   
    Most language packs consist of a single file with the .xml file extension. If the language pack you are installing contains other files, follow the instructions provided with the pack.
     
    To install the pack, navigate to Customization -> Languages in the AdminCP. Click the Create New button, and in the popup window, select the Upload tab. Choose the xml file that makes up the language pack.
    The Locale determines how numbers and dates are formatted in the software. The same language can be used in different locales; for example, English is used in the United States and the United Kingdom (among others), but these are different locales and use different date formats. Choose the locale that best matches your userbase (you can install the same language pack multiple times and use different locales for each, if you wanted).
    Click Save to install the language pack. You'll now see it in the language list; it is enabled and ready for users to use!
  31. Like
    Rikki got a reaction from TAMAN for a guide, ips.ui.chart   
    Description
    The Chart widget takes a specially-formatted table of data, and uses Google Charts to render it as an attractive chart.
    The Chart widget is designed for use soley with the output of the \IPS\Helpers\Chart class and is documented here for completeness only. Consult the documentation for the PHP class for more information.
     
    Options
    type
    (String; required)
    Specifies the type of chart to render, e.g. LineChart
     
    extraOptions
    (Object; optional)
    Object of extra options passed through to the Google Charts library.
     
    Events
    chartInitialized
    Triggered after the chart has been initialized.
  32. 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.
  33. Like
    Rikki got a reaction from sobrenome for a guide, Making it interactive with Javascript   
    We can now tie everything together with some Javascript. It's with the Javascript that everything will feel snappy and interactive. Begin by heading over to the template editor, and editing the Javascript file we created earlier.
    The Javascript controller we write will do two things:
    Load the first record when the page is loaded Handle click events on the other records to load the ones the user clicks Here's the final Javascript code you need to insert into the file. We'll explain it shortly:
     
    This is a standard IPS4 javascript controller; refer to the controller documentation for more information.
    In our initialize method (called automatically when the controller is initialized), we set up an event handler for clicking on elements with the data-releaseID attribute (if you remember, we gave items in our record listing this attribute). We bind this handler to the showRelease method.
    We then call the setup method. The logic in this method selects a record to load automatically, so that the page has content in it when the user first loads it. It tries to find a record with the data-currentRelease attribute, but if one doesn't exist, it will load the first item in the list instead.
    Finally, there's the showRelease method which has the job of loading and displaying the record view, pulled dynamically via AJAX. To do this, we find the relevant URL from the record row and then fire an AJAX request. In the done handler, we update the div that holds our record content.
    When a Pages URL is called via AJAX (whether it's a normal page, or a database), it will only return the page content - it won't include the complete site wrapper. This makes it a little easier to implement dynamic page loading. However, in our case, the HTML we need is actually even narrower - we want just the record content, not any of the surrounding page from Pages. For this reason, in the done handler we select just the contents of the #elCmsPageWrap element, and use that as our record content.
  34. 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.
  35. Like
    Rikki got a reaction from InvisionHQ for a guide, Making it interactive with Javascript   
    We can now tie everything together with some Javascript. It's with the Javascript that everything will feel snappy and interactive. Begin by heading over to the template editor, and editing the Javascript file we created earlier.
    The Javascript controller we write will do two things:
    Load the first record when the page is loaded Handle click events on the other records to load the ones the user clicks Here's the final Javascript code you need to insert into the file. We'll explain it shortly:
     
    This is a standard IPS4 javascript controller; refer to the controller documentation for more information.
    In our initialize method (called automatically when the controller is initialized), we set up an event handler for clicking on elements with the data-releaseID attribute (if you remember, we gave items in our record listing this attribute). We bind this handler to the showRelease method.
    We then call the setup method. The logic in this method selects a record to load automatically, so that the page has content in it when the user first loads it. It tries to find a record with the data-currentRelease attribute, but if one doesn't exist, it will load the first item in the list instead.
    Finally, there's the showRelease method which has the job of loading and displaying the record view, pulled dynamically via AJAX. To do this, we find the relevant URL from the record row and then fire an AJAX request. In the done handler, we update the div that holds our record content.
    When a Pages URL is called via AJAX (whether it's a normal page, or a database), it will only return the page content - it won't include the complete site wrapper. This makes it a little easier to implement dynamic page loading. However, in our case, the HTML we need is actually even narrower - we want just the record content, not any of the surrounding page from Pages. For this reason, in the done handler we select just the contents of the #elCmsPageWrap element, and use that as our record content.
  36. 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
  37. Like
    Rikki got a reaction from Jim M for a guide, Responsiveness   
    Introduction to responsive classes
    IPS4's CSS framework is responsive, meaning elements adapt according to the size of the display the users chooses to use. In most cases, the existing classes already outlined in this guide take care of it for you; for example, menus automatically adjust, and tab bars collapse into a dropdown menu on mobile phones.
    There may be times when you need to control on which devices sizes elements show or hide themselves. For example, if you add a custom footer element, you may want to only show it on desktop, and hide it from tablets or phones.
    The responsive classes that IPS4 provides allow you to control this kind of behavior.
     
    Responsive sizes used by IPS4
    For the purposes of the media queries we use to control responsiveness, the following sizes represent each device:
    Phones - up to 767 pixels wide Tablets - between 768 pixels and 979 pixels wide Desktops - 980 pixels and wider  
    Basic show/hide functionality
    The CSS framework includes two groups of three classes that show or hide elements on desktop, tablet and phone-sized devices, respectively. The classes act in an exclusive way; that is, if you use the show classes, any devices that don't match will not show the element. The opposite is also true; if you use the hide classes, then the element will not show on those devices but will show on the others not specified.
    The classes are:
    ipsResponsive_hidePhone ipsResponsive_hideTablet ipsResponsive_hideDesktop ipsResponsive_showPhone ipsResponsive_showTablet ipsResponsive_showDesktop You can combine these as needed. For example:
    <div class='ipsResponsive_hidePhone ipsResponsive_hideTablet'> This element *will not* display on phones or tablets, but *will* display on desktops </div>  
    Additional classes to control element display
    When using the show classes outlined above, you typically need to include an additional class that controls how the element is rendered. This can be one of the following:
    ipsResponsive_block ipsResponsive_inlineBlock ipsResponsive_inline <div class='ipsResponsive_showDesktop ipsResponsive_block'> This element will *only* show on desktop sizes, and will render as a block-level element. </div> These additional classes aren't usually necessary when using the hide classes.
  38. 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)
     
  39. 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
  40. 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
  41. 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
  42. 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.
  43. 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.
  44. 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  
  45. Like
    Rikki got a reaction from BomAleold for a guide, Making it interactive with Javascript   
    We can now tie everything together with some Javascript. It's with the Javascript that everything will feel snappy and interactive. Begin by heading over to the template editor, and editing the Javascript file we created earlier.
    The Javascript controller we write will do two things:
    Load the first record when the page is loaded Handle click events on the other records to load the ones the user clicks Here's the final Javascript code you need to insert into the file. We'll explain it shortly:
     
    This is a standard IPS4 javascript controller; refer to the controller documentation for more information.
    In our initialize method (called automatically when the controller is initialized), we set up an event handler for clicking on elements with the data-releaseID attribute (if you remember, we gave items in our record listing this attribute). We bind this handler to the showRelease method.
    We then call the setup method. The logic in this method selects a record to load automatically, so that the page has content in it when the user first loads it. It tries to find a record with the data-currentRelease attribute, but if one doesn't exist, it will load the first item in the list instead.
    Finally, there's the showRelease method which has the job of loading and displaying the record view, pulled dynamically via AJAX. To do this, we find the relevant URL from the record row and then fire an AJAX request. In the done handler, we update the div that holds our record content.
    When a Pages URL is called via AJAX (whether it's a normal page, or a database), it will only return the page content - it won't include the complete site wrapper. This makes it a little easier to implement dynamic page loading. However, in our case, the HTML we need is actually even narrower - we want just the record content, not any of the surrounding page from Pages. For this reason, in the done handler we select just the contents of the #elCmsPageWrap element, and use that as our record content.
  46. Like
    Rikki got a reaction from craigf136 for a guide, Using designer's mode   
    While the standard template editor is useful for light template editing, for larger, more complex changes, editing with a real IDE is desirable. The IPS Community Suite facilitates this through something called Designer's Mode.
     
    What is Designer's Mode?
    Designer's Mode allows you to use a real IDE by exporting all of the templates and CSS files to disk as files, and then reimporting them to the suite when you have finished editing them.
    With Designer's Mode enabled, the software will load its theme from this folder, meaning you can edit the files and see the changes as you make them.
    Warning Designer's Mode should not be used on a live community because it will have resource usage implications. We always recommend developing themes with Designer's Mode on a test/development installation.  
    Enabling Designer's Mode
    The first step is to create a folder called themes in your root community directory (that is, the same place your conf_global.php exists). CHMOD this folder to 777 to enable the suite to write the files.
    Next, navigate to Customization -> Themes in the AdminCP. In the toolbar at the top of the page, click the Designer's Mode button. Toggle the setting on after reading the information box, and then save the form. IPS4 will begin writing the theme files to disk.
    Once complete, you will see a directory structure similar to this in the /themes folder on your server:

    All themes currently installed are exported when Designer's Mode is enabled; the parent folders in this structure are named based on the theme ID. You can cross-reference the theme ID you wish to edit on the theme listing page in the AdminCP while Designer's Mode is enabled:

    Each theme folder contains four key parts:
    /css
    The CSS for the theme, grouped first by app, then by location (front/admin/global). /html
    The *.phtml HTML templates this theme uses, grouped first by app, then by location (front/admin/global) then by section. lang.php
    A language file into which you can insert any custom language strings your theme requires. They should be in this format: 'my_language_key' => "The English phrase"  
    /resources
    Resources for the theme (primarily images), grouped first by app, then by location (front/admin/global) then by type.
    Resources aren't allowed to be larger than 1.5 MB . 
     
    Editing templates
    When you edit the *.phtml template files exporting by Designer's Mode, you will notice a special tag on the first line of each file that looks like this:
    <ips:template parameters="$title,$html,$location=array()" /> This tag is how the software knows which variables belong to this template. It is very important that you do not modify this line in template files, or your theme may break.
     
    Completing Designer's Mode
    When you are happy with your changes, you can disable Designer's Mode to import them back into the suite (note that you can enable Designer's Mode again later to continue).
    To do this, go back to the theme listing screen at Customization -> Themes, and click the red Designer's Mode Enabled button. When you toggle the setting off, you will see additional settings asking you to confirm that you want to synchronize the changes.
    Warning Be sure the Synchronize option is enabled when you save this form, otherwise your changes will be lost.
    You can select individual themes to sync, or all of them. You can also choose whether to keep the files on disk or automatically delete them once the sync is done.
  47. 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.
  48. Like
    Rikki got a reaction from Meddysong for a guide, Making it interactive with Javascript   
    We can now tie everything together with some Javascript. It's with the Javascript that everything will feel snappy and interactive. Begin by heading over to the template editor, and editing the Javascript file we created earlier.
    The Javascript controller we write will do two things:
    Load the first record when the page is loaded Handle click events on the other records to load the ones the user clicks Here's the final Javascript code you need to insert into the file. We'll explain it shortly:
     
    This is a standard IPS4 javascript controller; refer to the controller documentation for more information.
    In our initialize method (called automatically when the controller is initialized), we set up an event handler for clicking on elements with the data-releaseID attribute (if you remember, we gave items in our record listing this attribute). We bind this handler to the showRelease method.
    We then call the setup method. The logic in this method selects a record to load automatically, so that the page has content in it when the user first loads it. It tries to find a record with the data-currentRelease attribute, but if one doesn't exist, it will load the first item in the list instead.
    Finally, there's the showRelease method which has the job of loading and displaying the record view, pulled dynamically via AJAX. To do this, we find the relevant URL from the record row and then fire an AJAX request. In the done handler, we update the div that holds our record content.
    When a Pages URL is called via AJAX (whether it's a normal page, or a database), it will only return the page content - it won't include the complete site wrapper. This makes it a little easier to implement dynamic page loading. However, in our case, the HTML we need is actually even narrower - we want just the record content, not any of the surrounding page from Pages. For this reason, in the done handler we select just the contents of the #elCmsPageWrap element, and use that as our record content.
  49. Like
    Rikki got a reaction from sudo for a guide, Making it interactive with Javascript   
    We can now tie everything together with some Javascript. It's with the Javascript that everything will feel snappy and interactive. Begin by heading over to the template editor, and editing the Javascript file we created earlier.
    The Javascript controller we write will do two things:
    Load the first record when the page is loaded Handle click events on the other records to load the ones the user clicks Here's the final Javascript code you need to insert into the file. We'll explain it shortly:
     
    This is a standard IPS4 javascript controller; refer to the controller documentation for more information.
    In our initialize method (called automatically when the controller is initialized), we set up an event handler for clicking on elements with the data-releaseID attribute (if you remember, we gave items in our record listing this attribute). We bind this handler to the showRelease method.
    We then call the setup method. The logic in this method selects a record to load automatically, so that the page has content in it when the user first loads it. It tries to find a record with the data-currentRelease attribute, but if one doesn't exist, it will load the first item in the list instead.
    Finally, there's the showRelease method which has the job of loading and displaying the record view, pulled dynamically via AJAX. To do this, we find the relevant URL from the record row and then fire an AJAX request. In the done handler, we update the div that holds our record content.
    When a Pages URL is called via AJAX (whether it's a normal page, or a database), it will only return the page content - it won't include the complete site wrapper. This makes it a little easier to implement dynamic page loading. However, in our case, the HTML we need is actually even narrower - we want just the record content, not any of the surrounding page from Pages. For this reason, in the done handler we select just the contents of the #elCmsPageWrap element, and use that as our record content.
  50. Like
    Rikki got a reaction from Teascu Dorin for a guide, Buttons   
    Basics
    The button classes described here can be applied to any element, although typically would be applied to an element like a, input[type="submit"] or button so that the user can interact with it.
    As a minimum, a button should receive the basic ipsButton class, plus a size class and a style class (explained below).
     
    Button styles
    ipsButton_normal
    Normal button ipsButton_primary
    Primary button ipsButton_alternate
    Alternate button ipsButton_important
    Important button ipsButton_light
    Light button ipsButton_veryLight
    Very light button ipsButton_overlaid
    Overlaid button ipsButton_link
    Link button  
    Button sizes
    ipsButton_medium
    Medium button ipsButton_verySmall
    Very small button ipsButton_small
    Small button ipsButton_large
    Large button ipsButton_veryLarge
    Very large button ipsButton_fullWidth
    Can be combined with another size, above.
    Full width button  
    Disabled buttons
    Buttons can be visually disabled either by adding the class ipsButton_disabled, or, on relevant input elements, adding the disabled property. For example:
    <a href='#' class='ipsButton ipsButton_normal ipsButton_medium ipsButton_disabled'>Disabled button (link)</a> <input type='submit' class='ipsButton ipsButton_normal ipsButton_medium' disabled value='Disabled button (input)'> These would render like so:
    Disabled button (link)  
    Split buttons
    Split buttons allow you to create toolbars easily by specifying a list of buttons that display joined to each other.
    They are created by specifying the class ipsButton_split on a wrapper element containing two or more buttons. The wrapper element can be a <ul> tag, or any other that makes sense for your use.
    All of the buttons in a split button group should be the same size, otherwise results are unpredictable. Different styles can be used on each button, though.
    <ul class='ipsButton_split'> <li><a href='#' class='ipsButton ipsButton_small ipsButton_primary'>Button 1</a></li> <li><a href='#' class='ipsButton ipsButton_small ipsButton_light'>Button 2</a></li> <li><a href='#' class='ipsButton ipsButton_small ipsButton_light'>Button 3</a></li> </ul> Button 1 Button 2 Button 3  
×
×
  • Create New...