Step 14: Use Custom Styles When the Component Is Rendered in an Inline Frame

Components rendered in an inline frame don't have direct access to the design.css file. Instead there is an additional step to get the URL for the design.css in your component and add it to the page. You then must update your component to reflect the user-selected style.

To include and use the design.css file in your component requires changes in the render.html file:
  1. Locate and include the URL to the design.css file

  2. Get the value of the select style class whenever it changes

  3. Update the template to reflect the styleClass selected

  4. Reflect changes to the selected style class in your component

  5. Make sure the inline frame resizes when the style changes

Here are the detailed instructions for editing the render.html file:

  1. Locate and include the URL to the design.css file.

    Dynamically add the design.css file to the <head> section of the page. After it has been loaded, set the height of the inline frame because it may have been altered by applying the styles.

    Add the following code into the viewModel object:

    // Dynamically add any theme design URL to the <head> of the page
    self.loadStyleSheet = function (url) {
        var $style,
            styleSheetDeferred = new $.Deferred(),
            attempts = 100,
            numAttempts = 0,
            interval = 50,
            pollFunction = function () {
                // try to locate the style sheet
                for (var i = 0; i < document.styleSheets.length; i++) {
                    try {
                        // locate the @import sheet that has an href based on our expected URL
                        var sheet = document.styleSheets[i],
                            rules = sheet && sheet.cssRules,
                            rule = rules && rules[0];
                        // check whether style sheet has been loaded
                        if (rule && (rule.href === url)) {
                            styleSheetDeferred.resolve();
                            return;
                        }
                    } catch (e) {}
                }
                if (numAttempts < attempts) {
                    numAttempts++;
                    setTimeout(pollFunction, interval);
                } else {
                    // didn't find style sheet so complete anyway
                    styleSheetDeferred.resolve();
                }
            };
     
        // add the themeDesign stylesheet to <head>
        // use @import to avoid cross domain security issues when determining when the stylesheet is loaded
        $style = $('<style type="text/css">@import url("' + url + '")</style>');
        $style.appendTo('head');
     
        // kickoff the polling
        pollFunction();
     
        // return the promise
        return styleSheetDeferred.promise();
    };
     
    // update with the design.css from the Sites Page
    SitesSDK.getSiteProperty('themeDesign', function (data) {
        if (data && data.themeDesign && typeof data.themeDesign === 'string') {
            // load the style sheet and then set the height
            self.loadStyleSheet(data.themeDesign).done(self.setHeight);
        }
    });
  2. Get the value of the select style class whenever it changes.

    Create an observable to track when the value of the styleClass property changes. :

    self.selectedStyleClass = ko.observable();

    Note that we can’t render until we have the style class. Change this code:

    self.customSettingsDataInitialized = ko.observable(false);
    self.initialized = ko.computed(function () {
        return self.customSettingsDataInitialized();
    }, self);

    Use this code instead:

    self.customSettingsDataInitialized = ko.observable(false);
    self.styleClassInitialized = ko.observable(false);
    self.initialized = ko.computed(function () {
        return self.customSettingsDataInitialized() && self.styleClassInitialized();
    }, self);

    Get the initial value for the selected style class by adding:

    self.updateStyleClass = function (styleClass) {
        self.selectedStyleClass((typeof styleClass === 'string') ? styleClass : 'hello-world-default-style'); // note that this 'hello-world' prefix is based on the app name
        self.styleClassInitialized(true);
    };
    SitesSDK.getProperty('styleClass', self.updateStyleClass);
  3. Update the template to reflect the styleClass . Change this code:

    <p data-bind="attr: {id: 'titleId'}, text: titleText"></p>

    Use this code instead:

    <p data-bind="attr: {id: 'titleId'}, text: titleText, css: selectedStyleClass"></p>
  4. Reflect changes to the selected style class in your component. Change this code:

    if (settings.property === 'customSettingsData') {
        self.updateCustomSettingsData(settings.value);
    }

    Use this code instead:

    if (settings.property === 'customSettingsData') {
        self.updateCustomSettingsData(settings.value);
    }
    if (settings.property === 'styleClass') {
        self.updateStyleClass(settings.value);
    }
  5. Make sure the inline frame re-sizes when the style changes. Change this code:

    // create dependencies on any observables so this handler is called whenever it changes
    var imageWidth = viewModel.imageWidth(),
          imageUrl = viewModel.imageUrl(),
          titleText = viewModel.titleText(),
          userText = viewModel.userText();

    Use this code instead:

    // create dependencies on any observables so this handler is called whenever it changes
    var imageWidth = viewModel.imageWidth(),
          imageUrl = viewModel.imageUrl(),
          titleText = viewModel.titleText(),
          userText = viewModel.userText(),
          selectedStyleClass = viewModel.selectedStyleClass();  
  6. Save and sync your files to the Oracle Content Management instance server.

Check the Results for Step 14

  1. Refresh your page in your site so Site Builder can pick up changes to the component.

  2. Take the page into Edit mode.

  3. Drag and drop your component onto the page.

  4. Bring up the Settings panel against your component.

  5. Go to the Style tab.

  6. Switch between Gothic and Plain styles defined in your design.json file.

    You’ll notice that the font size within your component adjusts to reflect the changes as it switches between the applied CSS class for each selection.

Continue to Step 15: Integration with the Page Undo and Redo Behavior.