ViewPort-JS

From HaFrWiki
Revision as of 17:09, 2 June 2017 by Hjmf (talk | contribs) (Created page with "{{TOCright}} Responsive Design is normally achieved by using the features of the CSS-Media queries. And that is also my preferred way of making Responsive applications. Pers...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Responsive Design is normally achieved by using the features of the CSS-Media queries. And that is also my preferred way of making Responsive applications. Personally I am using jQuery + Bootstrap. The responsive design of the input-forms is straightforward and the look-and-feel on Desktop and Mobile are good. The problem occurs when the app needs tables.

If you are using Bootstrap in combination with Bootgrid you have a problem when using the CSS. The columns of the grid are selectable in the applications and simply hiding a column with CSS won't help (the user will not understand that a selected column does not show up). So the app needs to change the selections in Bootgrid, but Bootgrid does not allow such an action. Also the GitHub-code [1] has not been changed since more than 2 years.

Bootgrid

Bootgrid [2] is an extension on jQuery especially designed for Bootstrap. Since the version-control-repository has not been altered since 2 years, I do not expect any major changes will be made.

Therefor I have created an extension to the code without altering the original Bootgrid code. The first extension makes it possible to change the selected columns in Bootgrid self <syntaxhighlight lang="javascript"> /**

 * Renders special HaFr queries
 * Needs to be calls as renderHaFr.call(this, json)
 * Is called by the prototype.hafr
 * @param  string  json json-list with pairs: column => (in)visible
 */
function renderHaFr(json) {
    var that     = this;
    var joParams = JSON.parse(json);
    var css      = this.options.css;
    var selector;
    $.each(Object.keys( joParams ), function( i, key) {
        $.each(that.columns, function (j, column) {
            if (column.visibleInSelection && column.id == key) {
                // Makes the column (in)visible.
                column.visible = joParams[key];
                renderTableHeader.call(that);
                // Adjust the listbox selections
                setDomNameVal( column.id, joParams[key]);
            }
        });
        loadData.call(that);
    });

} // renderHaFr </syntaxhighlight>

In my library setDomNameVal is a utility function <syntaxhighlight lang="javascript"> function setDomNameVal(domName, domValue) {

  'use strict';
  var nameSelector = '[name="' + domName + '"]';
  if ( $(nameSelector).length ) {
     if ( $(nameSelector).is(':checkbox')) {
        if ( domValue == 1 ) {
           $(nameSelector).prop('checked', true);
        } else {
           $(nameSelector).prop('checked', false  );
        }
     } else {
        $(nameSelector).val(domValue);
     }
  }

} // setDomNameVal </syntaxhighlight>

The second Bootgrid extension is a prototype function which enables the calling from outside, which calls the render function with the 'this' parameter/content. The prototype only implements the 'viewport' action. <syntaxhighlight lang="javascript"> /**

* HaFr specific function for all kind of special not implemented bootgrid functionalities.
* @param string action The requested HaFr action.
* @param string json   Parameters for the action
*/

Grid.prototype.hafr = function(action, json) {

   var met  = "grid.prototype.hafr";
    if (action == 'viewport') {
       renderHaFr.call(this, json);
   }

}; </syntaxhighlight>

ViewPort-JS.php

The used server language is PHP. To make the co-existence of JavaScript and PHP as easy as possible the JavaScript file is embedded in a PHP-file. For the simplicity the PHP wrapper is removed in the given code example. <syntaxhighlight lang="javascript"> /**

* Anonymous function for ViewPort Width x Height Changes or Orientation Changes.
* The changes has an implication on the settings of the Bootgrid lists.
* @param  object vpjs      Name for the function to be used to call the functions.
* @param  object $         Object jQuery is passed in.
* @param  object undefined Prevents the overriding of the undefined.
*/

(function( vpjs, $, undefined ) {

   'use strict';
  /** Version information */
  vpjs.versionNumber = "1.0.3.1";
  vpjs.versionDate   = "02 Jun 2017";
  /*
   * Enumerations for the action to take on the change of the viewport orientation and/or ranges.
   */
  vpjs.enumError  = -1;   // Error status.
  vpjs.enumStay   = 0;    // Do nothing.
  vpjs.enumHigh   = 1;    // Changed to the highest range.
  vpjs.enumMid    = 2;    // Changed to the mid-range.
  vpjs.enumLow    = 3;    // Changed to the lowest range.
  /* Private initialization flag. */
  var isInit = false;
   /**
    * Private property placeholder for the current Viewport.
    */
   var curViewPort     = { 'innerHeight' : 0, 'innerWidth': 0, 'isMobile': false, 'isLandscape': false, 'enum': vpjs.enumError };
   /**
    * Default Ranges for the Landscape mode.
    * Maybe overruled by the setter 'setRangeLandscape'.
   */
   var rangeLandscape  = { start: 100, low: 780, mid: 1040, high: 9999 };
   /**
    * Default Ranges for the Portrait mode.
    * Maybe overruled by the setter 'setRangePortrait'.
    */
   var rangePortrait   = { start: 100, low: 680, mid: 1040, high: 9999 };
   var cbOptions  = { version: vpjs.versionNumber };
   var cbFunction;
  /**
   * Public Initialization function remembers the current viewport and sets the init-flag.
   * The entry point for the function to be called like 'vpjs.init()'.
   */
  vpjs.init = function(options) {
     var met = "vpjs.init";
     isInit = true;
     saveViewPort();
     if (typeof options === 'undefined') {
        logts( sprintf( logFormatLBW, met, "options", "No options declared."))
        return;
     }
     if ( hasObjectProperty( options, 'cbFunction') ) {
        logts( sprintf( logFormatLBW, met, "cbFunction", "Set to " + cbFunction));
        cbFunction = window[ options.cbFunction ];
     }
     if ( hasObjectProperty( options, 'rangeLandscape') && checkRange( options.rangeLandscape ) ) {
        logts( sprintf( logFormatLBW, met, "rangeLandscape", "Set to " + JSON.stringify(options.rangeLandscape) ));
        rangeLandscape = options.rangeLandscape;
     }
     if ( hasObjectProperty( options, 'rangePortrait') && checkRange( options.rangePortrait ) ) {
        logts( sprintf( logFormatLBW, met, "rangePortrait", "Set to " + JSON.stringify(options.rangePortrait) ));
        rangePortrait = options.rangePortrait;
     }
   };  // vpjs.init
  /**
   * Public performs the initialization-action.
   * The initialization action has to be performed immediate after the function-initialization.
   * The performInitAction is optional.
   * Use this function to set the initial state at opening of the website when no responsive grid column settings are used.
   */
  vpjs.performInitAction = function() {
     var met = 'vpjs.performInitAction';
     // Saves the enum into the curViewPort-object.
     saveEnum4ViewPort();
     if (curViewPort.enum === vpjs.enumError) {
        logts( sprintf( logFormatLBW, met, "ERROR", "Requirements not met, nothing performed."));
     }
     // Calls the CallBack function.
     if (typeof cbFunction === "function") {
        cbFunction.call(null, cbOptions, curViewPort.enum );
     } else {
        logts( sprintf( logFormatLBW, met, "cbFunction", "Not a function!"));
     }
  }  // vpjs.performInitAction
  /**
   * Sets the callback function and the options.
   * @deprecated Use the method vpjs.init(options) instead.
   * @param object callOptions  The options
   * @param string callFunction The call back function as string without brackets and params.
   */
  vpjs.setCallBack = function(callOptions, callFunction) {
     var met = "vpjs.setCallBack";
     logts( sprintf( logFormatLBW, met, "Function", callFunction));
     cbOptions  = callOptions;
     cbFunction = window[callFunction];
  }   // setCallBack
  /**
   * Setter for the limits for the Landscape.
   * @param object range Object with keys: start, low, mid, high.
   */
  vpjs.setRangeLandscape = function(range) {
     if (checkRange(range) ) {
        rangeLandscape = range;
        return true;
     }
     logts( sprintf( logFormatLBW, met, "ERROR", "Invalid range."));
     return false;
  }   // setRangeLandscape
  /**
   * Setter for the limits for the Portrait
   * @param object range Object with keys: start, low, mid, high.
   */
  vpjs.setRangePortrait = function(range) {
     if (checkRange(range) ) {
        rangePortrait = range;
        return true;
     }
     logts( sprintf( logFormatLBW, met, "ERROR", "Invalid range."));
     return false;
  }   // setRangePortrait
  /**
   * Private checks the range for Landscape/Portrait.
   * @param  object range Range object with required keys.
   * @return boolean true | false
   */
  function checkRange(range) {
     var met = "checkRange";
     if ( hasObjectProperty( range, "start") === false ||
          hasObjectProperty( range, "low"  ) === false ||
          hasObjectProperty( range, "mid"  ) === false ||
          hasObjectProperty( range, "high" ) === false) {
        logts( sprintf( logFormatLBW, met, "Error", "Invalid range specification given."));
        return false;
     }
     return true;
  }   // checkRange
  /**
   * Public getter for the saved isMobile setting.
   * @return Boolean isMobile
   */
  vpjs.isMobile = function() {
     return curViewPort['isMobile'];
  }   // isMobile
  /**
   * Public getter for the saved isLandscape setting.
   * @return Boolean isLandscape
   */
  vpjs.isLandscape = function() {
     return curViewPort['isLandscape'];
  }   // isLandscape
  /**
   * Public entry for testing the change of orientation and/or range outbreak of the WxH in compare to the saved settings.
   * In case of an outbreak of saved settings:
   * - The needed actions are saved into the returned JavaScript object.
   * - The new settings overwrite the old saved settings.
   * @return JavaScript object aRet { transition: enumeration, ...}
   */
  vpjs.hasTransition = function() {
     // 'use strict';
     var met  = 'hasTransition';
     var aRet = {
        transition: vpjs.enumError,
        keywords: ,
        users: ,
        description: 
     };
     // Checks the initialization flag, returning an error if not set.
     if (! isInit) {
        return aRet;
     }
     if ( vpjs.hasChangedOrientation() ) {
        logtrace(sprintf( logFormatLBW, met, "Transition", "Orientation change detected"));
        aRet['transition'   ] = vpjs.enumStay;
        aRet['description'  ] = sprintf("%s (%ux%u)", 'Orientation change detected ', window.innerWidth, window.innerHeight);
        if (isLandscape() ) {
           if (window.innerWidth < rangeLandscape.low) {
              aRet['transition'] = vpjs.enumLow;
           } else if (window.innerWidth < rangeLandscape.mid) {
              aRet['transition'] = vpjs.enumMid;
           } else {
              aRet['transition'] = vpjs.enumHigh;
           }
        } else {
           if (window.innerWidth < rangePortrait.low) {
              aRet['transition'] = vpjs.enumLow;
           } else if (window.innerWidth < rangePortrait.mid) {
              aRet['transition'] = vpjs.enumMid;
           } else {
              aRet['transition'] = vpjs.enumHigh;
           }
        }
     } else if (vpjs.hasChangedViewPort() ) {
        if (isLandscape()) {
           aRet['transition'] = landscapeRanges( window.innerWidth );
        } else {
           aRet['transition'] = portraitRanges( window.innerWidth );
        }
        aRet['description'  ] = sprintf("Transition %u, %s (%ux%u)", aRet['transition'], 'WxH change detected ', window.innerWidth, window.innerHeight);
        logtrace(sprintf( logFormatLBW, met, "Transition", aRet['description']));
     }
     if (aRet['transition'] !== vpjs.enumStay) {
        saveViewPort();
        if (typeof cbFunction === "function") {
           cbFunction.call(null, cbOptions, aRet['transition']); // , aRet['transition']);
        } else {
           logts( sprintf( logFormatLBW, met, "cbFunction", "Not a function!"));
        }
     }
     return aRet;
  }   // vpjs.hasTransition


  /**
   * Private saves the current to curViewPort WxH and isMobile settings.
   */
  function saveViewPort() {
     'use strict';
     var met = 'saveViewPort';
     curViewPort['innerHeight'] = window.innerHeight;
     curViewPort['innerWidth' ] = window.innerWidth ;
     curViewPort['isMobile'   ] = isMobile();
     curViewPort['isLandscape'] = isLandscape();
     curViewPort['enum'       ] = vpjs.enumError;
  }
  /**
   * Saves the current enum (low-mid-high) into the viewport.
   * Needs the ranges to be set.
   */
  function saveEnum4ViewPort() {
     var met = "saveEnum4ViewPort";
     var range = rangeLandscape;
     if ( curViewPort.isLandcape === false ) {
        range = rangePortrait;
     }
     curViewPort.enum = vpjs.enumError;
     logts( sprintf(logFormatLBW, met, "range", JSON.stringify( range)));
     if (checkRange(range) === false) {
        return;
     }
     if ( range.start < curViewPort.innerWidth && curViewPort.innerWidth <= range.low  ) {
        curViewPort.enum = vpjs.enumLow;
     } else if ( range.low < curViewPort.innerWidth && curViewPort.innerWidth < range.mid ) {
        curViewPort.enum = vpjs.enumMid;
     } else if ( range.mid < curViewPort.innerWidth && curViewPort.innerWidth < range.high ) {
        curViewPort.enum = vpjs.enumHigh;
     } else {
        curViewPort.enum = vpjs.enumError;
     }
  }   // saveEnum4Viewport
  /**
   * Private test for changes in landscape mode of the WxH range settings the action-enumeration to none, high, mid or low.
   * @param  integer x The current value for the width.
   * @return enumeration action
   */
  function landscapeRanges(x) {
     if ( (isInRange( rangeLandscape.mid  , rangeLandscape.high, x) && isInRange( rangeLandscape.mid  , rangeLandscape.high , curViewPort['innerWidth'])) ||
            (isInRange( rangeLandscape.low  , rangeLandscape.mid , x) && isInRange( rangeLandscape.low  , rangeLandscape.mid  , curViewPort['innerWidth'])) ||
            (isInRange( rangeLandscape.start, rangeLandscape.low , x) && isInRange( rangeLandscape.start, rangeLandscape.low  , curViewPort['innerWidth'])) ) {
           return vpjs.enumStay;
     }
     if ( x != curViewPort['innerWidth']) {
        if ( isInRange( rangeLandscape.mid  , rangeLandscape.high, x) ) {
           return vpjs.enumHigh;
        }
        if ( isInRange( rangeLandscape.low  , rangeLandscape.mid, x) ) {
           return vpjs.enumMid;
        }
       if ( isInRange( rangeLandscape.start, rangeLandscape.low , x) ) {
           return vpjs.enumLow;
        }
     }
     return vpjs.enumStay;
  }   // landscapeRanges
  /**
   * Private test for changes in portrait mode of the WxH range settings the action-enumeration to none, high, mid or low.
   * @param  integer x The current value for the width.
   * @return enumeration action
   */
  function portraitRanges(x) {
     if ( (isInRange( rangePortrait.mid  , rangePortrait.high, x) && isInRange( rangePortrait.mid  , rangePortrait.high , curViewPort['innerWidth'])) ||
          (isInRange( rangePortrait.low  , rangePortrait.mid , x) && isInRange( rangePortrait.low  , rangePortrait.mid  , curViewPort['innerWidth'])) ||
          (isInRange( rangePortrait.start, rangePortrait.low , x) && isInRange( rangePortrait.start, rangePortrait.low  , curViewPort['innerWidth'])) ) {
        return vpjs.enumStay;
     }
     if ( x != curViewPort['innerWidth']) {
        if ( isInRange( rangePortrait.mid  , rangePortrait.high, x) ) {
           return vpjs.enumHigh;
        }
        if ( isInRange( rangePortrait.low  , rangePortrait.mid, x) ) {
           return vpjs.enumMid;
        }
        if ( isInRange( rangePortrait.start, rangePortrait.low, x) ) {
           return vpjs.enumLow;
        }
     }
     return vpjs.enumStay;
  }  // portraitRanges
  /**
   * Has the Viewport VxH changed versus the saved curViewPort?
   * @return Boolean true | false
   */
  vpjs.hasChangedViewPort = function() {
     'use strict';
     var met = 'hasChangedViewPort';
     if (curViewPort.innerHeight !== window.innerHeight) {
        logtrace( sprintf( logFormatLBW, met, "Height", curViewPort.innerHeight + " => " + window.innerHeight));
        return true;
     }
     if (curViewPort.innerWidth !== window.innerWidth) {
        logtrace( sprintf( logFormatLBW, met, "Width", curViewPort.innerWidth + " => " + window.innerWidth));
        return true;
     }
     return false;
  }  // hasChangedViewPort
  /**
   * Has the Viewport Orientation changed versus the saved curViewPort?
   * @return Boolean true | false
   */
  vpjs.hasChangedOrientation = function() {
     'use strict';
     var met = 'hasChangedOrientation';
     if (isLandscape() != curViewPort.isLandscape) {
        if (isLandscape() ) {
           logverbose( sprintf( logFormatLBW, met, "Orientation", "Portrait => Landscape"));
        } else {
           logverbose( sprintf( logFormatLBW, met, "Orientation", "Landscape => Portrait"));
        }
        return true;
     }
     return false;
  }  // has ChangedOrientation
  /**
   * Gets the string representation of the enumeration.
   * @param  enum   enum Action-enumeration
   * @return string String representation.
   */
  vpjs.strAction = function(enumVal) {
     switch(enumVal) {
        case vpjs.enumStay : return 'Stay';
        case vpjs.enumHigh : return 'High';
        case vpjs.enumMid  : return 'Mid' ;
        case vpjs.enumLow  : return 'Low' ;
        default            : return 'Unknown';
     }
     return 'Unknown';
  }   // vpjs.strAction

} ( window.vpjs = window.vpjs || {}, jQuery) ); </syntaxhighlight>

See also

top

Reference

top

  1. GitHub rstaib jquery-bootgrid, Git Repository from Rafael Straib for Bootgrid.
  2. jQuery Bootgrid an jQuery extension created by Rafael Staib.