<commit_before>/**
* html5tooltips.js
* Light and clean tooltips.
* https://github.com/yevhentiurin/html5tooltipsjs
*
* Yevhen Tiurin <yevhentiurin@gmail.com>
* The MIT License (MIT)
* http://opensource.org/licenses/MIT
*
* April 10, 2014
**/

(function() {

var tt, tModels, activeElements, documentReady,

typeTooltipModel = {
  contentText: "",
  contentMore: "",
  disableAnimation: false,
  stickTo: "bottom",
  targetElements: [],
  targetSelector: "",
  targetXPath: "",
  maxWidth: "auto"
},

template = {
  HTML: [
    "
",
      "

",
      "
",
        "

",
        "

",
      "
",
      "

",
    "
"
  ].join(""),

  hookClasses: {
    tooltip: 'html5tooltip',
    tooltipText: 'html5tooltip-text',
    tooltipMore: 'html5tooltip-more',
    tooltipMoreText: 'html5tooltip-text',
    tooltipPointer: 'html5tooltip-pointer'
  }
};

function toArray(obj)
{
  return Array.prototype.slice.call(obj);
}

function getElementsByXPath(xpath, context)
{
  var nodes = [];

  try {
    var result = document.evaluate(xpath, (context || document), null,
      XPathResult.ANY_TYPE, null);

    for (var item = result.iterateNext(); item; item = result.iterateNext())
      nodes.push(item);
  }
  catch (exc)
  {
    // Invalid xpath expressions make their way here sometimes. If that happens,
    // we still want to return an empty set without an exception.
  }

  return nodes;
}

function getElementsBySelector(selector, context)
{
  var nodes = [];

  try {
    nodes = toArray((context || document).querySelectorAll(selector));
  }
  catch (exc) {}

  return nodes;
}

function getElementsByAttribute(attr, context)
{
  var nodeList = (context || document).getElementsByTagName('*'),
    nodes = [];

  for (var i = 0, node; node = nodeList[i]; i++) {
    if ( node.getAttribute(attr) )
      nodes.push(node);
  }

  return nodes;
}

function extend(targetObj)
{
  for (var i = 1; i < arguments.length; i++) {
    if (typeof arguments[i] === "object") {
      for (var property in arguments[i]) {
        if (arguments[i].hasOwnProperty(property)) {
          targetObj[property] = arguments[i][property];
        }
      }
    }
  }

  return targetObj;
}

function Tooltip()
{
  var ttElement, ttModel, targetElement, elText, elMore, elMoreText, elPointer;

  function destroy()
  {
    document.removeChild(ttElement);
  }

  function disableAnimation()
  {
    toggleAnimation(false);

    return this;
  }

  function enableAnimation()
  {
    toggleAnimation(true);

    return this;
  }

  function hideAll()
  {
    if (ttElement.style.visibility !== 'collapse')
      ttElement.style.visibility = 'collapse';
      ttElement.style.opacity = '0';
      ttElement.style.left = '-9999px';
      ttElement.style.top = '-9999px';

    if (elMore.style.display !== 'none') {
      elMore.style.display = 'none';
      elMore.style.visibility = 'collapse';
      elMore.style.height = 'auto';
    }

    return this;
  }

  function init()
  {
    var tmplNode = document.createElement("div");
    tmplNode.innerHTML = template.HTML;
    ttElement = tmplNode.firstChild;
    document.body.appendChild(ttElement);

    // ttElement = document.getElementsByClassName(template.hookClasses.tooltip)[0];
    elText = ttElement.getElementsByClassName(template.hookClasses.tooltipText)[0];
    elMore = ttElement.getElementsByClassName(template.hookClasses.tooltipMore)[0];
    elMoreText = elMore.getElementsByClassName(template.hookClasses.tooltipMoreText)[0];
    elPointer = ttElement.getElementsByClassName(template.hookClasses.tooltipPointer)[0];

    hideAll();

    ttModel = extend({}, typeTooltipModel);
  }

  function model(userTTModel)
  {
    if (!userTTModel)
      return ttModel;

    if (ttModel !== userTTModel) {
      ttModel = extend({}, typeTooltipModel, userTTModel);
      updateModel();
    }

    return this;
  }

  function showBrief()
  {
    if (ttElement.style.visibility !== 'visible')
      ttElement.style.visibility = 'visible';
      ttElement.style.opacity = '1';

    updatePos();

    return this;
  }

  function showAll()
  {
    if (ttElement.style.visibility !== 'visible') {
      ttElement.style.visibility = 'visible';
      ttElement.style.opacity = '1';

      if (ttModel.contentMore) {
        elMore.style.display = 'block';
        elMore.style.visibility = 'visible';
      }

      updatePos();
    }
    else if (elMore.style.display !== 'block' && ttModel.contentMore) {
      elMore.style.display = 'block';

      updatePos();

      var h = elMore.getBoundingClientRect().height;
      elMore.style.visibility = 'visible';
      elMore.style.height = '0px';

      setTimeout(function() {
        elMore.style.height = h > 0 ? h + 'px' : "auto";
      }, 100);
    }

    return this;
  }

  function target(userTargetElement)
  {
    if (!userTargetElement)
      return targetElement;

    if (targetElement !== userTargetElement) {
      targetElement = userTargetElement;
    }

    return this;
  }

  function toggleAnimation(on)
  {
    ["t", "MozT", "MsT", "OT", "WebkitT"].forEach(function(pr) {
      ttElement.style[pr + "ransition"] = on ? "opacity 0.3s" : "";
      elMore.style[pr + "ransition"] = on ? "height 0.3s" : "";
    });

    return this;
  }

  function updatePos()
  {
    var targetRect, ttRect;

    if (!targetElement)
      return;

    // update width
    ttElement.style.width = "auto";
    ttRect = ttElement.getBoundingClientRect();
    if (ttModel.maxWidth !== "auto")
      ttElement.style.width = ttRect.width > ttModel.maxWidth ? ttModel.maxWidth + "px" : "auto";

    // position depend on target and tt width
    targetRect = targetElement.getBoundingClientRect();
    ttRect = ttElement.getBoundingClientRect();
    ttElement.style.left = targetRect.left + (targetRect.width - ttRect.width) / 2 + "px";
    ttElement.style.top = targetRect.top + targetRect.height + 10 + "px";

    elPointer.style.left = parseInt((ttRect.width - 12) / 2) + "px";
  }

  function updateModel()
  {
    elText.innerHTML = ttModel.contentText ? ttModel.contentText : "";
    elMoreText.innerHTML = ttModel.contentMore ? ttModel.contentMore : "";

    // update animation
    if (ttModel.disableAnimation)
      disableAnimation();
    else
      enableAnimation();
  }

  init();

  return {
    destroy: destroy,
    disableAnimation: disableAnimation,
    enableAnimation: enableAnimation,
    hideAll: hideAll,
    model: model,
    showAll: showAll,
    showBrief: showBrief,
    target: target,
    updatePos: updatePos
  };
}

function pickDocumentDataTargets()
{
  var pickedElements = getElementsByAttribute("data-tooltip-text");

  pickedElements.forEach(function(elTarget) {
    tModels.push(extend({}, typeTooltipModel, {
      contentText: elTarget.getAttribute("data-tooltip-text"),
      contentMore: elTarget.getAttribute("data-tooltip-more"),
      targetElements: [elTarget]
    }));
  });
}

function scroll()
{
  tt.updatePos();
}

function init()
{
  tt = Tooltip();

  activeElements = {
    focused: null,
    hovered: null
  };

  pickDocumentDataTargets();

  tModels.forEach(function(tModel, i) {
    tModel = extend({}, typeTooltipModel, tModel);

    if (!tModel.targetElements.length && tModel.targetSelector)
      tModel.targetElements = getElementsBySelector(tModel.targetSelector);

    if (!tModel.targetElements.length && tModel.targetXPath)
      tModel.targetElements = getElementsByXPath(tModel.targetXPath);

    tModel.targetElements.forEach(function(el) {
      el.addEventListener("mouseover", function() {
        var hoverTarget = this;

        if (activeElements.hovered === hoverTarget || activeElements.focused !== null)
          return;

        activeElements.hovered = hoverTarget;
        tt.target(this).model(tModel);

        setTimeout(function() {
          if (activeElements.hovered === hoverTarget)
            tt.showBrief();
        }, 300);
      });

      el.addEventListener("mouseout", function() {
        activeElements.hovered = null;

        if (activeElements.focused !== null)
          return;

        tt.hideAll();
      });

      el.addEventListener("focus", function() {
        if (["INPUT", "TEXTAREA"].indexOf(this.tagName) === -1)
          return;

        activeElements.focused = this;

        tt.target(this).model(tModel);
        tt.showAll();
      });

      el.addEventListener("blur", function() {
        activeElements.focused = null;
        tt.hideAll();
      });
    });

    tModels[i] = tModel;
  });
}

function html5tooltips(userTModels)
{
  if (!tModels)
    tModels = [];

  if (userTModels.length)
    // merge arrays
    Array.prototype.push.apply(tModels, userTModels);

  else if (typeof userTModels === "object")
    tModels.push(userTModels);

  if (documentReady)
    init();
}

function completed() {
  document.removeEventListener( "DOMContentLoaded", completed, false );
  window.removeEventListener( "load", completed, false );
  documentReady = true;

  init();
}

if (document.readyState === "complete")
  documentReady = true;

else {
  document.addEventListener("DOMContentLoaded", completed, false);
  window.addEventListener( "load", completed, false );
}

window.addEventListener( "scroll", scroll, false );

if (window.html5tooltips === undefined)
  window.html5tooltips = html5tooltips;

// define("html5tooltips", function () {
//   return html5tooltips;
// });

})();<commit_msg>Added AMD defenition<commit_after>/**
* html5tooltips.js
* Light and clean tooltips.
* https://github.com/yevhentiurin/html5tooltipsjs
*
* Yevhen Tiurin <yevhentiurin@gmail.com>
* The MIT License (MIT)
* http://opensource.org/licenses/MIT
*
* April 10, 2014
**/

(function() {

var tt, tModels, activeElements, documentReady,

typeTooltipModel = {
  contentText: "",
  contentMore: "",
  disableAnimation: false,
  stickTo: "bottom",
  targetElements: [],
  targetSelector: "",
  targetXPath: "",
  maxWidth: "auto"
},

template = {
  HTML: [
    "
",
      "

",
      "
",
        "

",
        "

",
      "
",
      "

",
    "
"
  ].join(""),

  hookClasses: {
    tooltip: 'html5tooltip',
    tooltipText: 'html5tooltip-text',
    tooltipMore: 'html5tooltip-more',
    tooltipMoreText: 'html5tooltip-text',
    tooltipPointer: 'html5tooltip-pointer'
  }
};

function toArray(obj)
{
  return Array.prototype.slice.call(obj);
}

function getElementsByXPath(xpath, context)
{
  var nodes = [];

  try {
    var result = document.evaluate(xpath, (context || document), null,
      XPathResult.ANY_TYPE, null);

    for (var item = result.iterateNext(); item; item = result.iterateNext())
      nodes.push(item);
  }
  catch (exc)
  {
    // Invalid xpath expressions make their way here sometimes. If that happens,
    // we still want to return an empty set without an exception.
  }

  return nodes;
}

function getElementsBySelector(selector, context)
{
  var nodes = [];

  try {
    nodes = toArray((context || document).querySelectorAll(selector));
  }
  catch (exc) {}

  return nodes;
}

function getElementsByAttribute(attr, context)
{
  var nodeList = (context || document).getElementsByTagName('*'),
    nodes = [];

  for (var i = 0, node; node = nodeList[i]; i++) {
    if ( node.getAttribute(attr) )
      nodes.push(node);
  }

  return nodes;
}

function extend(targetObj)
{
  for (var i = 1; i < arguments.length; i++) {
    if (typeof arguments[i] === "object") {
      for (var property in arguments[i]) {
        if (arguments[i].hasOwnProperty(property)) {
          targetObj[property] = arguments[i][property];
        }
      }
    }
  }

  return targetObj;
}

function Tooltip()
{
  var ttElement, ttModel, targetElement, elText, elMore, elMoreText, elPointer;

  function destroy()
  {
    document.removeChild(ttElement);
  }

  function disableAnimation()
  {
    toggleAnimation(false);

    return this;
  }

  function enableAnimation()
  {
    toggleAnimation(true);

    return this;
  }

  function hideAll()
  {
    if (ttElement.style.visibility !== 'collapse')
      ttElement.style.visibility = 'collapse';
      ttElement.style.opacity = '0';
      ttElement.style.left = '-9999px';
      ttElement.style.top = '-9999px';

    if (elMore.style.display !== 'none') {
      elMore.style.display = 'none';
      elMore.style.visibility = 'collapse';
      elMore.style.height = 'auto';
    }

    return this;
  }

  function init()
  {
    var tmplNode = document.createElement("div");
    tmplNode.innerHTML = template.HTML;
    ttElement = tmplNode.firstChild;
    document.body.appendChild(ttElement);

    // ttElement = document.getElementsByClassName(template.hookClasses.tooltip)[0];
    elText = ttElement.getElementsByClassName(template.hookClasses.tooltipText)[0];
    elMore = ttElement.getElementsByClassName(template.hookClasses.tooltipMore)[0];
    elMoreText = elMore.getElementsByClassName(template.hookClasses.tooltipMoreText)[0];
    elPointer = ttElement.getElementsByClassName(template.hookClasses.tooltipPointer)[0];

    hideAll();

    ttModel = extend({}, typeTooltipModel);
  }

  function model(userTTModel)
  {
    if (!userTTModel)
      return ttModel;

    if (ttModel !== userTTModel) {
      ttModel = extend({}, typeTooltipModel, userTTModel);
      updateModel();
    }

    return this;
  }

  function showBrief()
  {
    if (ttElement.style.visibility !== 'visible')
      ttElement.style.visibility = 'visible';
      ttElement.style.opacity = '1';

    updatePos();

    return this;
  }

  function showAll()
  {
    if (ttElement.style.visibility !== 'visible') {
      ttElement.style.visibility = 'visible';
      ttElement.style.opacity = '1';

      if (ttModel.contentMore) {
        elMore.style.display = 'block';
        elMore.style.visibility = 'visible';
      }

      updatePos();
    }
    else if (elMore.style.display !== 'block' && ttModel.contentMore) {
      elMore.style.display = 'block';

      updatePos();

      var h = elMore.getBoundingClientRect().height;
      elMore.style.visibility = 'visible';
      elMore.style.height = '0px';

      setTimeout(function() {
        elMore.style.height = h > 0 ? h + 'px' : "auto";
      }, 100);
    }

    return this;
  }

  function target(userTargetElement)
  {
    if (!userTargetElement)
      return targetElement;

    if (targetElement !== userTargetElement) {
      targetElement = userTargetElement;
    }

    return this;
  }

  function toggleAnimation(on)
  {
    ["t", "MozT", "MsT", "OT", "WebkitT"].forEach(function(pr) {
      ttElement.style[pr + "ransition"] = on ? "opacity 0.3s" : "";
      elMore.style[pr + "ransition"] = on ? "height 0.3s" : "";
    });

    return this;
  }

  function updatePos()
  {
    var targetRect, ttRect;

    if (!targetElement)
      return;

    // update width
    ttElement.style.width = "auto";
    ttRect = ttElement.getBoundingClientRect();
    if (ttModel.maxWidth !== "auto")
      ttElement.style.width = ttRect.width > ttModel.maxWidth ? ttModel.maxWidth + "px" : "auto";

    // position depend on target and tt width
    targetRect = targetElement.getBoundingClientRect();
    ttRect = ttElement.getBoundingClientRect();
    ttElement.style.left = targetRect.left + (targetRect.width - ttRect.width) / 2 + "px";
    ttElement.style.top = targetRect.top + targetRect.height + 10 + "px";

    elPointer.style.left = parseInt((ttRect.width - 12) / 2) + "px";
  }

  function updateModel()
  {
    elText.innerHTML = ttModel.contentText ? ttModel.contentText : "";
    elMoreText.innerHTML = ttModel.contentMore ? ttModel.contentMore : "";

    // update animation
    if (ttModel.disableAnimation)
      disableAnimation();
    else
      enableAnimation();
  }

  init();

  return {
    destroy: destroy,
    disableAnimation: disableAnimation,
    enableAnimation: enableAnimation,
    hideAll: hideAll,
    model: model,
    showAll: showAll,
    showBrief: showBrief,
    target: target,
    updatePos: updatePos
  };
}

function pickDocumentDataTargets()
{
  var pickedElements = getElementsByAttribute("data-tooltip-text");

  pickedElements.forEach(function(elTarget) {
    tModels.push(extend({}, typeTooltipModel, {
      contentText: elTarget.getAttribute("data-tooltip-text"),
      contentMore: elTarget.getAttribute("data-tooltip-more"),
      targetElements: [elTarget]
    }));
  });
}

function scroll()
{
  tt.updatePos();
}

function init()
{
  tt = Tooltip();

  activeElements = {
    focused: null,
    hovered: null
  };

  pickDocumentDataTargets();

  tModels.forEach(function(tModel, i) {
    tModel = extend({}, typeTooltipModel, tModel);

    if (!tModel.targetElements.length && tModel.targetSelector)
      tModel.targetElements = getElementsBySelector(tModel.targetSelector);

    if (!tModel.targetElements.length && tModel.targetXPath)
      tModel.targetElements = getElementsByXPath(tModel.targetXPath);

    tModel.targetElements.forEach(function(el) {
      el.addEventListener("mouseover", function() {
        var hoverTarget = this;

        if (activeElements.hovered === hoverTarget || activeElements.focused !== null)
          return;

        activeElements.hovered = hoverTarget;
        tt.target(this).model(tModel);

        setTimeout(function() {
          if (activeElements.hovered === hoverTarget)
            tt.showBrief();
        }, 300);
      });

      el.addEventListener("mouseout", function() {
        activeElements.hovered = null;

        if (activeElements.focused !== null)
          return;

        tt.hideAll();
      });

      el.addEventListener("focus", function() {
        if (["INPUT", "TEXTAREA"].indexOf(this.tagName) === -1)
          return;

        activeElements.focused = this;

        tt.target(this).model(tModel);
        tt.showAll();
      });

      el.addEventListener("blur", function() {
        activeElements.focused = null;
        tt.hideAll();
      });
    });

    tModels[i] = tModel;
  });
}

function html5tooltips(userTModels)
{
  if (!tModels)
    tModels = [];

  if (userTModels.length)
    // merge arrays
    Array.prototype.push.apply(tModels, userTModels);

  else if (typeof userTModels === "object")
    tModels.push(userTModels);

  if (documentReady)
    init();
}

function completed() {
  document.removeEventListener( "DOMContentLoaded", completed, false );
  window.removeEventListener( "load", completed, false );
  documentReady = true;

  init();
}

if (window.define) {
  // AMD
  documentReady = true;

  define("html5tooltips", function () {
    return html5tooltips;
  });

} else {
  // global object
  if (document.readyState === "complete")
    documentReady = true;

  else {
    document.addEventListener("DOMContentLoaded", completed, false);
    window.addEventListener( "load", completed, false );
  }

  window.addEventListener( "scroll", scroll, false );

  if (window.html5tooltips === undefined)
    window.html5tooltips = html5tooltips;
}

})();<|endoftext|>


<commit_before>var _ = require('underscore');
var moment = require('moment');

var _IDkey = '_id'; //"id";
module.exports._IDkey = _IDkey;
var _typekey = '__t'; //"type";
module.exports._typekey = _typekey;
var _versionkey = '__v'; //"version";
module.exports._versionkey = _versionkey;

function trueTypeof(value) {
    if (value === null) {
        return "null";
    }
    var t = typeof value;
    switch(t) {
        case "function":
        case "object":
            if (value.constructor) {
                if (value.constructor.name) {
                    return value.constructor.name;
                } else {
                    // Internet Explorer
                    // Anonymous functions are stringified as follows: 'function () {}'
                    // => the regex below does not match
                    var match = value.constructor.toString().match(/^function (.+)\(.*$/);
                    if (match) {
                        return match[1];
                    }
                }
            }
            // fallback, for nameless constructors etc.
            return Object.prototype.toString.call(value).match(/^\[object (.+)\]$/)[1];
        default:
            return t;
    }
};

// like the python dictionary pop.
// return obj[prop] and remove property from obj.
// if obj[prop] doesn't exist, return default value.
function pyPop(obj, prop, defaultValue){
   obj = (obj === undefined) ? {} : obj;

   if(obj.hasOwnProperty(prop)){
       var rv =  obj[prop];
       delete obj[prop];
       return rv;
   } else {
       return defaultValue;
   }
}

module.exports.dataform = function(context){
    context = context || {};
    var df = {
      version : '0.1.0',
      // default to GMT
      displayTz: context.tz || 'Z'
    };

    // ---------------------------------
    //  private vars and methods
    // ---------------------------------
     var ostack = []; // context stack

   function o(){
       return ostack[ostack.length-1];
   }

   // may have an additional merge obj, with more key->value pairs.
   // They are all merged into the referenced html_attrs object, and the function
   // returns a string of the key/values formatted for inclusion and html attributes.
   function kwtoattr(html_attrs, merge){
      var k,v;
      var rv = '';
      if (merge) {
       for (k in merge) {
         if (merge.hasOwnProperty(k)) {
           v = merge[k];
           if(html_attrs.hasOwnProperty(k)){
              v = html_attrs[k] + ' ' + v
           }
           html_attrs[k] = v
         }
       }
     }

     var booleanAttributes = " hidden novalidate formnovalidate readonly required multiple autofocus disabled selected";

       for (k in html_attrs){
          if(!html_attrs.hasOwnProperty(k) || typeof html_attrs[k] !== 'string')
            continue;

          if (booleanAttributes.indexOf(" " + k + " ") > -1) {
            if (html_attrs[k]==k || html_attrs[k]=="") //otherwise omit
              rv += k + " ";
          } else {
           rv += k + '= "' + html_attrs[k].replace(/&/g,'&').replace(/"/g,'"') + '" ';
         }
       }
       return rv;
   }

   // return value of property in object.
   function resolve(obj, propstr, default_val){
       // special case, no test and assignment needed for optional default_val;  we don't mind if default_val is undefined!
       // note: eval called on propstr!
       var rv;

       if(obj === undefined){
           rv =  default_val;
       } else if(obj.hasOwnProperty(propstr)) {
           rv =  obj[propstr];
       } else {
           //treat [] as index 0
           propstr = propstr.replace(/\[\]/g,'[0]');
           // try drilling down complex propstr like 'foo.bar.quux' or array.
           try {
             //eval like this to enable "with {}" in strict mode (for babel compatibility)
             rv = (new Function( "with(this) { return " + propstr + "}")).call(obj);
           } catch(e) {
               rv = undefined;
           }
       }
       return (rv === undefined ) ? default_val : rv;
   }

   function getObj(obj){
      if(obj === undefined) {
          return o();  // if no o key in param object passed in, just use current object.
      } else {
          if(trueTypeof(obj) === 'string') {
              // if o is a string, treat it as a property name of current object.
              return resolve(o(), obj);
          } else {
              // if a legit non-string object itself, return it directly.
              return obj;
          }
      }
   }

   function setFormBindClass(val, html_attrs, nullAsJSON){
      var btype, bindClass;
      var type = typeof val;
      if(type === 'string') {
          return '';  // normal string: don't bother with string.
      } else if (type === 'object') {
          if (val === null && !nullAsJSON) {
            btype = 'null';
          } else if (val instanceof Date) {
            btype = 'date';
          } else {
            btype = 'json';
          }
      } else if (type === 'boolean'){
          btype = 'boolean'
      } else if(type === 'number'){
          btype = 'number'
      } else {
         btype = null;
      }

      bindClass = "type[" + btype + "]";
      if(btype !== null && html_attrs){
          var _class = html_attrs['class'] || '';
          if(_class !== '' && (_class !== undefined) ) {
             if( _class.search(/type\[(.*)\]/) === -1) {
                 // type specification not already in _class string: add it.
                html_attrs['class'] = _class + ' ' + bindClass;
             }
          } else {
              html_attrs['class'] = bindClass;
          }
      }
      return bindClass;
   }

   function serializeValue(val){
       if(val === undefined || val === null){
           return ''
       } else if (typeof val === 'string'){
           return val;
       } else if (val instanceof Date) {
         //adjust time to timezone to display
          return moment(val).utcOffset(df.displayTz).format('YYYY-MM-DDTHH:mm:ss.SSS');
         return v;
       } else {
           return JSON.stringify(val);
       }
   }

   // ------------------------------------------------------
   //     Exported methods
   // ------------------------------------------------------

   df.opush = function(oin){
       ostack.push(oin);
       return o();
   }

   df.opop = function(){
       return ostack.pop();
   }

  df.getVal = function(prop) {
     return getObj(prop);
   }

   df.formhandler = function(method, callback) {
      method = method || 'dbUpdate';
      callback = callback || '';
      return "$(document).on('submit', '.dbform', function() { \n $(this)."
              + method +  "(" + callback + "); \n return false; });";
   }

   df.form = function(obj,html_attrs){
       html_attrs = html_attrs || {};
       var rv = '<form ' + kwtoattr(html_attrs, {'class': 'dbform'}) + '>';
       if(obj[_IDkey] !== undefined){
           rv += "\n" + '<input type= "hidden" name= "'+ _IDkey + '" value= "' + obj[_IDkey] + '" />';
       }
       if(obj[_typekey] !== undefined){
           rv += "\n" + '<input type= "hidden" name= "'+ _typekey +'" value= "' + obj[_typekey] + '" />';
       }
       if(obj[_versionkey] !== undefined){
           rv += "\n" + '<input type= "hidden" name= "'+ _versionkey +'" value= "' + obj[_versionkey] + '" />';
       }
       df.opush(obj);
       return rv;
   }
   df.form.safe = true;

   df.form_end = function(){
       df.opop();
       return '</form>';
   }
   df.form_end.safe = true;

   function getInputType(value, defaultType) {
     if (typeof value === 'boolean') {
       return 'checkbox';
     } else if (typeof value === 'number') {
      return 'number';
     }  else if (value instanceof Date) {
      return 'datetime-local';
     }
     return defaultType || 'text';
   }

   df.input = function(prop, html_attrs, obj){
       html_attrs = _(html_attrs || {}).clone();
       var itype = pyPop(html_attrs,'type', 'text');
       if (itype === 'textarea') {
        return df.textarea(prop, html_attrs, obj);
       }
       var rv = '';
       var obj = getObj(obj);
       var value = resolve(obj, prop, pyPop(html_attrs, 'defaultValue'));
       if (pyPop(html_attrs, 'guessInputType')) {
         itype = getInputType(value, itype);
       }
       var toggleInput = (itype === 'radio' || itype === 'checkbox');
       var bindClass = setFormBindClass(value,html_attrs,toggleInput);
       if (bindClass === 'type[date]') {
         html_attrs['data-tz'] = df.displayTz;
       }
       if(!html_attrs.hasOwnProperty(value)){
           if(toggleInput && !value){
               if(html_attrs.hasOwnProperty('defaultOnValue')){
                   html_attrs['value'] = html_attrs['defaultOnValue'];
                   delete html_attrs['defaultOnValue'];
               } else {
                   if(bindClass === 'type[string]' || bindClass === undefined || bindClass === '' || bindClass === null){
                       html_attrs['value'] = 'on';
                   } else if (bindClass === 'type[number]'){
                       html_attrs['value'] = '1';
                   } else if (bindClass === 'type[boolean]' || bindClass === 'type[json]'){
                       html_attrs['value'] = 'true';
                   } else {
                       //XXX exception NIY : unexpected bindclass "%s" when setting a default unchecked value
                   }
               }
           } else {
               html_attrs['value'] = serializeValue(value);
           }
        }
       if(!prop) {prop = '';}
       rv = '<input type= "' + itype + '" ' + kwtoattr(html_attrs) + ' name= "' + prop + '" ';
       rv += (toggleInput && value ? 'checked ' : '') + '/>';
       return rv;
   }
   df.input.safe = true;

   df.hidden = function(prop, htmlAttrs, obj){
       htmlAttrs= _(htmlAttrs || {}).clone();
       var obj = getObj(obj);
       var value = resolve(obj, prop, pyPop(htmlAttrs,'defaultValue'));
       setFormBindClass(value,htmlAttrs);
       if(!htmlAttrs.hasOwnProperty('value')){
           htmlAttrs['value'] = serializeValue(value);
       }
       return '<input type="hidden" name= "' + prop + '" ' + kwtoattr(htmlAttrs) + '/>';
   }
   df.hidden.safe = true;

   df.textarea = function(prop, htmlAttrs, obj){
       htmlAttrs= _(htmlAttrs || {}).clone();
       var obj = getObj(obj);
       var value = resolve(obj, prop, pyPop(htmlAttrs, 'defaultValue'));
       setFormBindClass(value, htmlAttrs);
       return '<textarea name="' + prop + '" ' + kwtoattr(htmlAttrs) + '>'
        + value.replace(/&/g,'&').replace(/</g,'<') + '</textarea>';
   }
   df.textarea.safe = true;

   function generateOptions(options, selection, valuekey, labelkey, forceValue){
       var rv = '';
       for(var i = 0; i < options.length; i++){
           var value, label, htmlattr;
           if (typeof options[i] !== 'object') {
             label = value = options[i];
             htmlattr = {};
           } else {
             htmlattr = _(options[i]).clone();
             value = pyPop(htmlattr,
               htmlattr[_IDkey] !== undefined ? _IDkey : valuekey);
             label = pyPop(htmlattr,labelkey);
           }
           setFormBindClass(value, htmlattr);
           if (selection(value)) {
             htmlattr.selected = '';
           }
           if (value !== label || forceValue)
              htmlattr.value = serializeValue(value);
           rv += '<option ' + kwtoattr(htmlattr) + '>';
           rv += serializeValue(label).replace(/&/g,'&').replace(/</g,'<');
           rv += '</option>\n';
       }
       return rv;
   }

   df.select = function(prop, options, htmlAttrs){
       htmlAttrs= _(htmlAttrs || {}).clone();
       var rv = '';
       var obj = getObj();
       var labelkey = pyPop(htmlAttrs, 'labelKey', 'label');
       var valuekey = pyPop(htmlAttrs, 'valueKey', "value");
       var forceValue = pyPop(htmlAttrs, 'forceValue');
       var selection = resolve(obj, prop, pyPop(htmlAttrs, 'defaultValue'));
       var isArray = Array.isArray(selection);
       if (isArray) {
           prop += '[]';
       }
       if (pyPop(htmlAttrs, 'setBindType')) {
         setFormBindClass(isArray ? selection[0] : selection, htmlAttrs);
       }
       rv += '<select name= "' + prop + '" ' + kwtoattr(htmlAttrs) + (isArray ? 'multiple >' : '>');

       var objectLabelKey = pyPop(htmlAttrs, 'objectLabelKey');
       var objectValueKey = pyPop(htmlAttrs, 'objectValueKey');
       var selectedFunc = function(value) {
         if (selection === undefined || selection === null) {
           return false;
         } else if (isArray) {
           return selection.indexOf(value) > -1;
         } else if (objectValueKey) {
           return selection[objectValueKey] == value;
         } else {
           return selection == value;
         }
       }
       var optionArray = options;
       if (!optionArray) {
         optionArray = _.map(isArray && selection || [selection], function(val) {
           var obj = {};
           if (val && objectLabelKey) {
             obj[labelkey] = val[objectLabelKey];
             obj[valuekey] = val[objectValueKey];
           } else {
             obj[labelkey] = obj[valuekey] = val;
           }
           return obj;
         });
       }
       rv +=  generateOptions(optionArray,selectedFunc, valuekey, labelkey, forceValue);
       rv += '</select>';
       return rv;
   }
   df.select.safe = true;

   return df;
}
<commit_msg>better fix<commit_after>var _ = require('underscore');
var moment = require('moment');

var _IDkey = '_id'; //"id";
module.exports._IDkey = _IDkey;
var _typekey = '__t'; //"type";
module.exports._typekey = _typekey;
var _versionkey = '__v'; //"version";
module.exports._versionkey = _versionkey;

function trueTypeof(value) {
    if (value === null) {
        return "null";
    }
    var t = typeof value;
    switch(t) {
        case "function":
        case "object":
            if (value.constructor) {
                if (value.constructor.name) {
                    return value.constructor.name;
                } else {
                    // Internet Explorer
                    // Anonymous functions are stringified as follows: 'function () {}'
                    // => the regex below does not match
                    var match = value.constructor.toString().match(/^function (.+)\(.*$/);
                    if (match) {
                        return match[1];
                    }
                }
            }
            // fallback, for nameless constructors etc.
            return Object.prototype.toString.call(value).match(/^\[object (.+)\]$/)[1];
        default:
            return t;
    }
};

// like the python dictionary pop.
// return obj[prop] and remove property from obj.
// if obj[prop] doesn't exist, return default value.
function pyPop(obj, prop, defaultValue){
   obj = (obj === undefined) ? {} : obj;

   if(obj.hasOwnProperty(prop)){
       var rv =  obj[prop];
       delete obj[prop];
       return rv;
   } else {
       return defaultValue;
   }
}

module.exports.dataform = function(context){
    context = context || {};
    var df = {
      version : '0.1.0',
      // default to GMT
      displayTz: context.tz || 'Z'
    };

    // ---------------------------------
    //  private vars and methods
    // ---------------------------------
     var ostack = []; // context stack

   function o(){
       return ostack[ostack.length-1];
   }

   // may have an additional merge obj, with more key->value pairs.
   // They are all merged into the referenced html_attrs object, and the function
   // returns a string of the key/values formatted for inclusion and html attributes.
   function kwtoattr(html_attrs, merge){
      var k,v;
      var rv = '';
      if (merge) {
       for (k in merge) {
         if (merge.hasOwnProperty(k)) {
           v = merge[k];
           if(html_attrs.hasOwnProperty(k)){
              v = html_attrs[k] + ' ' + v
           }
           html_attrs[k] = v
         }
       }
     }

     var booleanAttributes = " hidden novalidate formnovalidate readonly required multiple autofocus disabled selected";

       for (k in html_attrs){
          if(!html_attrs.hasOwnProperty(k) || typeof html_attrs[k] !== 'string')
            continue;

          if (booleanAttributes.indexOf(" " + k + " ") > -1) {
            if (html_attrs[k]==k || html_attrs[k]=="") //otherwise omit
              rv += k + " ";
          } else {
           rv += k + '= "' + html_attrs[k].replace(/&/g,'&').replace(/"/g,'"') + '" ';
         }
       }
       return rv;
   }

   // return value of property in object.
   function resolve(obj, propstr, default_val){
       // special case, no test and assignment needed for optional default_val;  we don't mind if default_val is undefined!
       // note: eval called on propstr!
       var rv;

       if(obj === undefined){
           rv =  default_val;
       } else if(obj.hasOwnProperty(propstr)) {
           rv =  obj[propstr];
       } else {
           //treat [] as index 0
           propstr = propstr.replace(/\[\]/g,'[0]');
           // try drilling down complex propstr like 'foo.bar.quux' or array.
           try {
             //eval like this to enable "with {}" in strict mode (for babel compatibility)
             rv = (new Function( "with(this) { return " + propstr + "}")).call(obj);
           } catch(e) {
               rv = undefined;
           }
       }
       return (rv === undefined ) ? default_val : rv;
   }

   function getObj(obj){
      if(obj === undefined) {
          return o();  // if no o key in param object passed in, just use current object.
      } else {
          if(trueTypeof(obj) === 'string') {
              // if o is a string, treat it as a property name of current object.
              return resolve(o(), obj);
          } else {
              // if a legit non-string object itself, return it directly.
              return obj;
          }
      }
   }

   function setFormBindClass(val, html_attrs, nullAsJSON){
      var btype, bindClass;
      var type = typeof val;
      if(type === 'string') {
          return '';  // normal string: don't bother with string.
      } else if (type === 'object') {
          if (val === null && !nullAsJSON) {
            btype = 'null';
          } else if (val instanceof Date) {
            btype = 'date';
          } else {
            btype = 'json';
          }
      } else if (type === 'boolean'){
          btype = 'boolean'
      } else if(type === 'number'){
          btype = 'number'
      } else {
         btype = null;
      }

      bindClass = "type[" + btype + "]";
      if(btype !== null && html_attrs){
          var _class = html_attrs['class'] || '';
          if(_class !== '' && (_class !== undefined) ) {
             if( _class.search(/type\[(.*)\]/) === -1) {
                 // type specification not already in _class string: add it.
                html_attrs['class'] = _class + ' ' + bindClass;
             }
          } else {
              html_attrs['class'] = bindClass;
          }
      }
      return bindClass;
   }

   function serializeValue(val){
       if(val === undefined || val === null){
           return ''
       } else if (typeof val === 'string'){
           return val;
       } else if (val instanceof Date) {
         //adjust time to timezone to display
          return moment(val).utcOffset(df.displayTz).format('YYYY-MM-DDTHH:mm:ss.SSS');
         return v;
       } else {
           return JSON.stringify(val);
       }
   }

   // ------------------------------------------------------
   //     Exported methods
   // ------------------------------------------------------

   df.opush = function(oin){
       ostack.push(oin);
       return o();
   }

   df.opop = function(){
       return ostack.pop();
   }

  df.getVal = function(prop) {
     return getObj(prop);
   }

   df.formhandler = function(method, callback) {
      method = method || 'dbUpdate';
      callback = callback || '';
      return "$(document).on('submit', '.dbform', function() { \n $(this)."
              + method +  "(" + callback + "); \n return false; });";
   }

   df.form = function(obj,html_attrs){
       html_attrs = html_attrs || {};
       var rv = '<form ' + kwtoattr(html_attrs, {'class': 'dbform'}) + '>';
       if(obj[_IDkey] !== undefined){
           rv += "\n" + '<input type= "hidden" name= "'+ _IDkey + '" value= "' + obj[_IDkey] + '" />';
       }
       if(obj[_typekey] !== undefined){
           rv += "\n" + '<input type= "hidden" name= "'+ _typekey +'" value= "' + obj[_typekey] + '" />';
       }
       if(obj[_versionkey] !== undefined){
           rv += "\n" + '<input type= "hidden" name= "'+ _versionkey +'" value= "' + obj[_versionkey] + '" />';
       }
       df.opush(obj);
       return rv;
   }
   df.form.safe = true;

   df.form_end = function(){
       df.opop();
       return '</form>';
   }
   df.form_end.safe = true;

   function getInputType(value, defaultType) {
     if (typeof value === 'boolean') {
       return 'checkbox';
     } else if (typeof value === 'number') {
      return 'number';
     }  else if (value instanceof Date) {
      return 'datetime-local';
     }
     return defaultType || 'text';
   }

   df.input = function(prop, html_attrs, obj){
       html_attrs = _(html_attrs || {}).clone();
       var itype = pyPop(html_attrs,'type', 'text');
       if (itype === 'textarea') {
        return df.textarea(prop, html_attrs, obj);
       }
       var rv = '';
       var obj = getObj(obj);
       var value = resolve(obj, prop, pyPop(html_attrs, 'defaultValue'));
       if (pyPop(html_attrs, 'guessInputType')) {
         itype = getInputType(value, itype);
       }
       var toggleInput = (itype === 'radio' || itype === 'checkbox');
       var bindClass = setFormBindClass(value,html_attrs,toggleInput);
       if (bindClass === 'type[date]') {
         html_attrs['data-tz'] = df.displayTz;
       }
       if(!html_attrs.hasOwnProperty(value)){
           if(toggleInput && !value){
               if(html_attrs.hasOwnProperty('defaultOnValue')){
                   html_attrs['value'] = html_attrs['defaultOnValue'];
                   delete html_attrs['defaultOnValue'];
               } else {
                   if(bindClass === 'type[string]' || bindClass === undefined || bindClass === '' || bindClass === null){
                       html_attrs['value'] = 'on';
                   } else if (bindClass === 'type[number]'){
                       html_attrs['value'] = '1';
                   } else if (bindClass === 'type[boolean]' || bindClass === 'type[json]'){
                       html_attrs['value'] = 'true';
                   } else {
                       //XXX exception NIY : unexpected bindclass "%s" when setting a default unchecked value
                   }
               }
           } else {
               html_attrs['value'] = serializeValue(value);
           }
        }
       if(!prop) {prop = '';}
       rv = '<input type= "' + itype + '" ' + kwtoattr(html_attrs) + ' name= "' + prop + '" ';
       rv += (toggleInput && value ? 'checked ' : '') + '/>';
       return rv;
   }
   df.input.safe = true;

   df.hidden = function(prop, htmlAttrs, obj){
       htmlAttrs= _(htmlAttrs || {}).clone();
       var obj = getObj(obj);
       var value = resolve(obj, prop, pyPop(htmlAttrs,'defaultValue'));
       setFormBindClass(value,htmlAttrs);
       if(!htmlAttrs.hasOwnProperty('value')){
           htmlAttrs['value'] = serializeValue(value);
       }
       return '<input type="hidden" name= "' + prop + '" ' + kwtoattr(htmlAttrs) + '/>';
   }
   df.hidden.safe = true;

   df.textarea = function(prop, htmlAttrs, obj){
       htmlAttrs= _(htmlAttrs || {}).clone();
       var obj = getObj(obj);
       var value = resolve(obj, prop, pyPop(htmlAttrs, 'defaultValue'));
       setFormBindClass(value, htmlAttrs);
       return '<textarea name="' + prop + '" ' + kwtoattr(htmlAttrs) + '>'
        + value.replace(/&/g,'&').replace(/</g,'<') + '</textarea>';
   }
   df.textarea.safe = true;

   function generateOptions(options, isSelected, valuekey, labelkey, forceValue){
       var rv = '';
       for(var i = 0; i < options.length; i++){
           var value, label, htmlattr;
           if (typeof options[i] !== 'object') {
             label = value = options[i];
             htmlattr = {};
           } else {
             htmlattr = _(options[i]).clone();
             value = pyPop(htmlattr,
               htmlattr[_IDkey] !== undefined ? _IDkey : valuekey);
             label = pyPop(htmlattr,labelkey);
           }
           setFormBindClass(value, htmlattr);
           if (isSelected(value)) {
             htmlattr.selected = '';
           }
           if (value !== label || forceValue)
              htmlattr.value = serializeValue(value);
           rv += '<option ' + kwtoattr(htmlattr) + '>';
           rv += serializeValue(label).replace(/&/g,'&').replace(/</g,'<');
           rv += '</option>\n';
       }
       return rv;
   }

   df.select = function(prop, options, htmlAttrs){
       htmlAttrs= _(htmlAttrs || {}).clone();
       var rv = '';
       var obj = getObj();
       var labelkey = pyPop(htmlAttrs, 'labelKey', 'label');
       var valuekey = pyPop(htmlAttrs, 'valueKey', "value");
       var forceValue = pyPop(htmlAttrs, 'forceValue');
       var selection = resolve(obj, prop, pyPop(htmlAttrs, 'defaultValue'));
       var isArray = Array.isArray(selection);
       if (isArray) {
           prop += '[]';
       }
       if (pyPop(htmlAttrs, 'setBindType')) {
         setFormBindClass(isArray ? selection[0] : selection, htmlAttrs);
       }
       rv += '<select name= "' + prop + '" ' + kwtoattr(htmlAttrs) + (isArray ? 'multiple >' : '>');

       var objectLabelKey = pyPop(htmlAttrs, 'objectLabelKey');
       var objectValueKey = pyPop(htmlAttrs, 'objectValueKey');
       var selectedFunc = function(value) {
         if (selection === undefined) {
           return false;
         } else if (isArray) {
           return selection.indexOf(value) > -1;
         } else if (objectValueKey) {
           return selection && selection[objectValueKey] == value;
         } else {
           return selection == value;
         }
       }
       var optionArray = options;
       if (!optionArray) {
         optionArray = _.map(isArray && selection || [selection], function(val) {
           var obj = {};
           if (val && objectLabelKey) {
             obj[labelkey] = val[objectLabelKey];
             obj[valuekey] = val[objectValueKey];
           } else {
             obj[labelkey] = obj[valuekey] = val;
           }
           return obj;
         });
       }
       rv +=  generateOptions(optionArray,selectedFunc, valuekey, labelkey, forceValue);
       rv += '</select>';
       return rv;
   }
   df.select.safe = true;

   return df;
}
<|endoftext|>


<commit_before>
module.exports = function(portfinder, server, colors){
    portfinder.basePort = 3000;	//default port
    portfinder.getPort(function (err, port) {
        server.listen(port);
        console.log(colors.green('IOChat running on port: ' + port));
    });
};<commit_msg>default port to 80<commit_after>
module.exports = function(portfinder, server, colors){
    portfinder.basePort = 80;	//default port
    portfinder.getPort(function (err, port) {
        server.listen(port);
        console.log(colors.green('IOChat running on port: ' + port));
    });
}; <|endoftext|>


<commit_before>Meteor.publish('bets', function(){
  return Bets.find();
});

Meteor.publish('betNotifications', function(username){
  return BetNotifications.find({ toNotify: username });
});

Meteor.publish('messages', function(){
  return Messages.find();
});

Meteor.publish('allUsernames', function(){
  return Meteor.users.find();
});

Meteor.publish('images', function(){
  return Images.find();

});

Meteor.publish("friendsList", function() {
  return Friends.find();
});

 Meteor.publish("myFriends", function(userId) {
  return Friends.find({ user: userId })
 })

<commit_msg>only publish current_user bets<commit_after>Meteor.publish('bets', function(){
  return Bets.find();
});

Meteor.publish('myBets', function(username) {
  return Bets.find({
    bettors: username
  });
});

Meteor.publish('betNotifications', function(username){
  return BetNotifications.find({ toNotify: username });
});

Meteor.publish('messages', function(){
  return Messages.find();
});

Meteor.publish('allUsernames', function(){
  return Meteor.users.find();
});

Meteor.publish('images', function(){
  return Images.find();

});

Meteor.publish("friendsList", function() {
  return Friends.find();
});

 Meteor.publish("myFriends", function(userId) {
  return Friends.find({ user: userId })
 })

<|endoftext|>


<commit_before>Meteor.publish('tutors', function (selector, options) {
  check(options, {
    sort: Object,
    limit: Number
  })
  check (selector, Object)
  return Tutors.find(selector, options)
})

Meteor.publish('tutorprofiles', function () {
  return Tutors.find()
}) //required to work

Meteor.publish('singleTutor', (id) => {
  check(id, String)
  return Tutors.find(id)
})
<commit_msg>testing publication tweaks<commit_after>Meteor.publish('tutors', function (selector, options) {
  check(options, {
    sort: Object,
    limit: Number
  })
  check (selector, Object)
  return Tutors.find(selector, options)
})

Meteor.publish('tutorprofiles', function () {
  return Tutors.find({})
}) //required to work

Meteor.publish('singleTutor', (id) => {
  check(id, String)
  return Tutors.find(id)
})
<|endoftext|>


<commit_before>Meteor.publish('all-posts', function () {
    return Posts.find();
});

Meteor.publish('limited-posts', function () {
    return Posts.find({}, {
        limit: 2,
        sort: {timeCreated:  -1}
    });
});

Meteor.publish('specificfields-posts', function () {
    return Posts.find({}, {
        fields: {
            title: 1
        }
    });
});

Meteor.publish('lazyload-posts', function (limit) {
    return Posts.find({}, {
        limit: limit,
        fields: {
            text: 0
        },
        sort: {timeCreated: -1}
    });
});

Meteor.publish('single-post', function (slug) {
    return Posts.find({slug: slug});
});
<commit_msg>User roles publication.<commit_after>Meteor.publish('all-posts', function () {
    return Posts.find();
});

Meteor.publish('limited-posts', function () {
    return Posts.find({}, {
        limit: 2,
        sort: {timeCreated:  -1}
    });
});

Meteor.publish('specificfields-posts', function () {
    return Posts.find({}, {
        fields: {
            title: 1
        }
    });
});

Meteor.publish('lazyload-posts', function (limit) {
    return Posts.find({}, {
        limit: limit,
        fields: {
            text: 0
        },
        sort: {timeCreated: -1}
    });
});

Meteor.publish('single-post', function (slug) {
    return Posts.find({slug: slug});
});

Meteor.publish("userRoles", function () {
    if (this.userId) {
        return Meteor.users.find(this.userId, {fields: {roles: 1}});
    } else {
        this.ready();
    }
});
<|endoftext|>


<commit_before>/*
 * Licensed to Apereo under one or more contributor license
 * agreements. See the NOTICE file distributed with this work
 * for additional information regarding copyright ownership.
 * Apereo licenses this file to you under the Apache License,
 * Version 2.0 (the "License"); you may not use this file
 * except in compliance with the License.  You may obtain a
 * copy of the License at the following location:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
'use strict';

define(['angular'], function(angular) {
  return angular.module('portal.messages.services', [])
    .factory('messagesService', [
      '$http',
      '$log',
      '$localStorage',
      '$sessionStorage',
      '$q',
      '$filter',
      '$rootScope',
      'portalGroupService',
      'miscService',
      'keyValueService',
      'SERVICE_LOC',
      'MESSAGES',
      'KV_KEYS',
      function($http,
               $log,
               $localStorage,
               $sessionStorage,
               $q,
               $filter,
               $rootScope,
               portalGroupService,
               miscService,
               keyValueService,
               SERVICE_LOC,
               MESSAGES,
               KV_KEYS) {
        // Service messages
        var GET_MESSAGES_FAILED = 'Could not get notifications at this time.';
        // //////////////////
        // Exposed methods //
        // //////////////////

        /**
         * @typedef {Object} Message
         * @property {number} id
         * @property {string} title
         * @property {string} goLiveDate
         * @property {string} expireDate
         * @property {string} priority
         * @property {Boolean} dismissible
         * @property {Object} actionButton
         * @property {Object} moreInfoButton
         */

        /**
         * Get everything at the messages service endpoint
         * @return {Array} An array of message objects
         */
        var getAllMessages = function() {
          return $http.get(SERVICE_LOC.messagesURL)
            .then(function(response) {
              if (response.data && response.data.messages
                && angular.isArray(response.data.messages)) {
                return response.data.messages;
              } else {
                return GET_MESSAGES_FAILED;
              }
            })
            .catch(function(error) {
              miscService.redirectUser(error.status, 'Get all messages');
              return GET_MESSAGES_FAILED;
            });
        };

        /**
         * Filter the array of messages based on each message's groups
         * attribute
         * @param {Array} messages - An array of message objects
         * @return {Array} A filtered array of messages
         */
        var getMessagesByGroup = function(messages) {
          return portalGroupService.getGroups()
            .then(function(groups) {
              var messagesByGroup = [];
              angular.forEach(messages, function(message) {
                var added = false;
                // If the message's groups array has groups,
                // check for matches against portal groups
                if (message.audienceFilter && message.audienceFilter.groups
                  && message.audienceFilter.groups.length > 0) {
                  // For each group for the current message
                  angular.forEach(message.audienceFilter.groups,
                    function(messageGroup) {
                      if (!added) {
                        // Check for matches against the groups returned
                        // by portalGroupService
                        angular.forEach(groups,
                          function(group) {
                            if (!added && (group.name === messageGroup)) {
                              messagesByGroup.push(message);
                              added = true;
                            }
                          });
                      }
                    });
                } else {
                  // If the message's groups array is empty or null or
                  // non-existent, show it to everyone
                  messagesByGroup.push(message);
                  added = true;
                }
              });
              return messagesByGroup;
            })
            .catch(function(error) {
              $log.warn('Problem getting groups from portalGroupService');
              $log.warn(error);
              miscService.redirectUser(
                error.status, 'Unable to retrieve groups');
            });
        };

        /**
         * Filter the array of messages based on if
         * data was requested before showing
         * @param {Array} messages An array of message objects
         * @return {filteredMessages[]} an array of messages that
         *   includes only non-data messages and messages that requested
         *   data and had data
         */
        var getMessagesByData = function(messages) {
          // Initialize method variables
          var promises = [];
          var filteredMessages = [];

          angular.forEach(messages, function(message) {
            if (message.data && message.data.dataUrl) {
              // If the message has a dataUrl, add it to promises array
              promises.push($http.get(message.data.dataUrl, {cache: true})
                .then(function(result) {
                  var objectToFind = result.data;

                  // if dataMessageTitle is specified, use it
                  if (objectToFind && message.data.dataMessageTitle &&
                    angular.isArray(message.data.dataMessageTitle)) {
                    var messageTitle = objectToFind;
                    var messageTitleLocation =
                      message.data.dataMessageTitle;
                    angular.forEach(messageTitleLocation, function(value, key) {
                      messageTitle = messageTitle[value];
                    });
                    message.title = messageTitle;
                  }

                  // if dataMessageLearnMoreUrl is specified, use it
                  if (objectToFind &&
                      message.data.dataMessageMoreInfoUrl &&
                      message.moreInfoButton && angular.isArray(
                    message.data.dataMessageMoreInfoUrl)) {
                    var messageMoreInfoUrl = objectToFind;
                    var messageMoreInfoUrlLocation =
                      message.data.dataMessageMoreInfoUrl;
                    angular.forEach(messageMoreInfoUrlLocation,
                      function(value, key) {
                      messageMoreInfoUrl = messageMoreInfoUrl[value];
                    });
                    message.moreInfoButton.url = messageMoreInfoUrl;
                  }

                  // If dataObject specified, try to use it
                  if (result && message.data.dataObject) {
                    objectToFind =
                      objectToFind[message.data.dataObject];
                  }
                  // If dataArrayFilter specified, then use it to filter
                  if (objectToFind && message.data.dataArrayFilter) {
                    var arrayFilter = angular.fromJson(
                      message.data.dataArrayFilter
                    );
                    // If you try to do an array filter on a non-array,
                    // return blank
                    if (!angular.isArray(objectToFind)) {
                      return;
                    }
                    if ($filter('filter')(
                        objectToFind,
                        arrayFilter
                      ).length > 0) {
                      return message;
                    }
                  } else if (objectToFind) {
                    return message;
                  }
                  return;
                }).catch(function(error) {
                  if (message) {
                    $log.warn(
                      'Error retrieving data for notification ' + message.id);
                  }
                  $log.error(error);
                }
              ));
            } else {
              filteredMessages.push(message);
            }
          });

          // Once all the promises are prepared, run 'em
          return $q.all(promises)
            .then(function(result) {
              angular.forEach(result, function(message) {
                if (message) {
                  filteredMessages.push(message);
                }
              });
              return filteredMessages;
            });
        };

        /**
         * Get list of seen message IDs from K/V store or session storage
         * @return {*}
         */
        var getSeenMessageIds = function() {
          // If K/V store isn't turned on, don't proceed
          if (!keyValueService.isKVStoreActivated()) {
            return $q.resolve([]);
          }

          return keyValueService.getValue(KV_KEYS.VIEWED_MESSAGE_IDS)
            .then(function(result) {
              if (result && angular.isArray(result)) {
                return result;
              }
              return $q.reject(result);
            })
            .catch(function(error) {
              return [];
            });
        };

        /**
         * Set list of seen IDs in K/V store and session storage
         * @param {Array} originalSeenIds - The ids when the
         *    controller initialized
         * @param {Array} alteredSeenIds - The ids following action in
         *    the controller
         * @param {string} action - The action to take (restore or dismiss)
         * @return {*}
         */
        var setMessagesSeen = function(originalSeenIds,
                                       alteredSeenIds,
                                       action) {
          // If K/V store isn't activated, don't proceed
          if (!keyValueService.isKVStoreActivated()) {
            return $q.resolve($sessionStorage.seenMessageIds);
          }

          // Update stored IDs based on the action taken
          if (action === 'restore') {
            // If original array has values no longer present
            // in updated array, remove them
            //
            angular.forEach(originalSeenIds, function(id, index) {
              if (alteredSeenIds.indexOf(id) == -1) {
                originalSeenIds.splice(index, 1);
              }
            });
          } else if (action === 'dismiss') {
            // Add any IDs in the updated array to the original array
            angular.forEach(alteredSeenIds, function(id) {
              if (originalSeenIds.indexOf(id) == -1) {
                originalSeenIds.push(id);
              }
            });
          }
          return keyValueService.setValue(KV_KEYS.VIEWED_MESSAGE_IDS,
            originalSeenIds)
            .then(function() {
              $rootScope.$emit('notificationChange');
              return originalSeenIds;
            })
            .catch(function(error) {
              $log.warn('Problem setting seen message IDs in storage');
              return error;
            });
        };

        /**
         * Notify listeners that priority notifications flag has changed
         * @param {boolean} hasNotifications
         */
        var broadcastPriorityFlag = function(hasNotifications) {
          $rootScope.$broadcast('HAS_PRIORITY_NOTIFICATIONS',
            {hasNotifications: hasNotifications}
          );

          // Update storage
          $localStorage.hasPriorityNotifications = hasNotifications;
        };

        return {
          getAllMessages: getAllMessages,
          getMessagesByGroup: getMessagesByGroup,
          getMessagesByData: getMessagesByData,
          getSeenMessageIds: getSeenMessageIds,
          setMessagesSeen: setMessagesSeen,
          broadcastPriorityFlag: broadcastPriorityFlag,
        };
    }]);
});
<commit_msg>cache notifications<commit_after>/*
 * Licensed to Apereo under one or more contributor license
 * agreements. See the NOTICE file distributed with this work
 * for additional information regarding copyright ownership.
 * Apereo licenses this file to you under the Apache License,
 * Version 2.0 (the "License"); you may not use this file
 * except in compliance with the License.  You may obtain a
 * copy of the License at the following location:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
'use strict';

define(['angular'], function(angular) {
  return angular.module('portal.messages.services', [])
    .factory('messagesService', [
      '$http',
      '$log',
      '$localStorage',
      '$sessionStorage',
      '$q',
      '$filter',
      '$rootScope',
      'portalGroupService',
      'miscService',
      'keyValueService',
      'SERVICE_LOC',
      'MESSAGES',
      'KV_KEYS',
      function($http,
               $log,
               $localStorage,
               $sessionStorage,
               $q,
               $filter,
               $rootScope,
               portalGroupService,
               miscService,
               keyValueService,
               SERVICE_LOC,
               MESSAGES,
               KV_KEYS) {
        // Service messages
        var GET_MESSAGES_FAILED = 'Could not get notifications at this time.';
        // //////////////////
        // Exposed methods //
        // //////////////////

        /**
         * @typedef {Object} Message
         * @property {number} id
         * @property {string} title
         * @property {string} goLiveDate
         * @property {string} expireDate
         * @property {string} priority
         * @property {Boolean} dismissible
         * @property {Object} actionButton
         * @property {Object} moreInfoButton
         */

        /**
         * Get everything at the messages service endpoint
         * @return {Array} An array of message objects
         */
        var getAllMessages = function() {
          return $http.get(SERVICE_LOC.messagesURL, {cache: true})
            .then(function(response) {
              if (response.data && response.data.messages
                && angular.isArray(response.data.messages)) {
                return response.data.messages;
              } else {
                return GET_MESSAGES_FAILED;
              }
            })
            .catch(function(error) {
              miscService.redirectUser(error.status, 'Get all messages');
              return GET_MESSAGES_FAILED;
            });
        };

        /**
         * Filter the array of messages based on each message's groups
         * attribute
         * @param {Array} messages - An array of message objects
         * @return {Array} A filtered array of messages
         */
        var getMessagesByGroup = function(messages) {
          return portalGroupService.getGroups()
            .then(function(groups) {
              var messagesByGroup = [];
              angular.forEach(messages, function(message) {
                var added = false;
                // If the message's groups array has groups,
                // check for matches against portal groups
                if (message.audienceFilter && message.audienceFilter.groups
                  && message.audienceFilter.groups.length > 0) {
                  // For each group for the current message
                  angular.forEach(message.audienceFilter.groups,
                    function(messageGroup) {
                      if (!added) {
                        // Check for matches against the groups returned
                        // by portalGroupService
                        angular.forEach(groups,
                          function(group) {
                            if (!added && (group.name === messageGroup)) {
                              messagesByGroup.push(message);
                              added = true;
                            }
                          });
                      }
                    });
                } else {
                  // If the message's groups array is empty or null or
                  // non-existent, show it to everyone
                  messagesByGroup.push(message);
                  added = true;
                }
              });
              return messagesByGroup;
            })
            .catch(function(error) {
              $log.warn('Problem getting groups from portalGroupService');
              $log.warn(error);
              miscService.redirectUser(
                error.status, 'Unable to retrieve groups');
            });
        };

        /**
         * Filter the array of messages based on if
         * data was requested before showing
         * @param {Array} messages An array of message objects
         * @return {filteredMessages[]} an array of messages that
         *   includes only non-data messages and messages that requested
         *   data and had data
         */
        var getMessagesByData = function(messages) {
          // Initialize method variables
          var promises = [];
          var filteredMessages = [];

          angular.forEach(messages, function(message) {
            if (message.data && message.data.dataUrl) {
              // If the message has a dataUrl, add it to promises array
              promises.push($http.get(message.data.dataUrl, {cache: true})
                .then(function(result) {
                  var objectToFind = result.data;

                  // if dataMessageTitle is specified, use it
                  if (objectToFind && message.data.dataMessageTitle &&
                    angular.isArray(message.data.dataMessageTitle)) {
                    var messageTitle = objectToFind;
                    var messageTitleLocation =
                      message.data.dataMessageTitle;
                    angular.forEach(messageTitleLocation, function(value, key) {
                      messageTitle = messageTitle[value];
                    });
                    message.title = messageTitle;
                  }

                  // if dataMessageLearnMoreUrl is specified, use it
                  if (objectToFind &&
                      message.data.dataMessageMoreInfoUrl &&
                      message.moreInfoButton && angular.isArray(
                    message.data.dataMessageMoreInfoUrl)) {
                    var messageMoreInfoUrl = objectToFind;
                    var messageMoreInfoUrlLocation =
                      message.data.dataMessageMoreInfoUrl;
                    angular.forEach(messageMoreInfoUrlLocation,
                      function(value, key) {
                      messageMoreInfoUrl = messageMoreInfoUrl[value];
                    });
                    message.moreInfoButton.url = messageMoreInfoUrl;
                  }

                  // If dataObject specified, try to use it
                  if (result && message.data.dataObject) {
                    objectToFind =
                      objectToFind[message.data.dataObject];
                  }
                  // If dataArrayFilter specified, then use it to filter
                  if (objectToFind && message.data.dataArrayFilter) {
                    var arrayFilter = angular.fromJson(
                      message.data.dataArrayFilter
                    );
                    // If you try to do an array filter on a non-array,
                    // return blank
                    if (!angular.isArray(objectToFind)) {
                      return;
                    }
                    if ($filter('filter')(
                        objectToFind,
                        arrayFilter
                      ).length > 0) {
                      return message;
                    }
                  } else if (objectToFind) {
                    return message;
                  }
                  return;
                }).catch(function(error) {
                  if (message) {
                    $log.warn(
                      'Error retrieving data for notification ' + message.id);
                  }
                  $log.error(error);
                }
              ));
            } else {
              filteredMessages.push(message);
            }
          });

          // Once all the promises are prepared, run 'em
          return $q.all(promises)
            .then(function(result) {
              angular.forEach(result, function(message) {
                if (message) {
                  filteredMessages.push(message);
                }
              });
              return filteredMessages;
            });
        };

        /**
         * Get list of seen message IDs from K/V store or session storage
         * @return {*}
         */
        var getSeenMessageIds = function() {
          // If K/V store isn't turned on, don't proceed
          if (!keyValueService.isKVStoreActivated()) {
            return $q.resolve([]);
          }

          return keyValueService.getValue(KV_KEYS.VIEWED_MESSAGE_IDS)
            .then(function(result) {
              if (result && angular.isArray(result)) {
                return result;
              }
              return $q.reject(result);
            })
            .catch(function(error) {
              return [];
            });
        };

        /**
         * Set list of seen IDs in K/V store and session storage
         * @param {Array} originalSeenIds - The ids when the
         *    controller initialized
         * @param {Array} alteredSeenIds - The ids following action in
         *    the controller
         * @param {string} action - The action to take (restore or dismiss)
         * @return {*}
         */
        var setMessagesSeen = function(originalSeenIds,
                                       alteredSeenIds,
                                       action) {
          // If K/V store isn't activated, don't proceed
          if (!keyValueService.isKVStoreActivated()) {
            return $q.resolve($sessionStorage.seenMessageIds);
          }

          // Update stored IDs based on the action taken
          if (action === 'restore') {
            // If original array has values no longer present
            // in updated array, remove them
            //
            angular.forEach(originalSeenIds, function(id, index) {
              if (alteredSeenIds.indexOf(id) == -1) {
                originalSeenIds.splice(index, 1);
              }
            });
          } else if (action === 'dismiss') {
            // Add any IDs in the updated array to the original array
            angular.forEach(alteredSeenIds, function(id) {
              if (originalSeenIds.indexOf(id) == -1) {
                originalSeenIds.push(id);
              }
            });
          }
          return keyValueService.setValue(KV_KEYS.VIEWED_MESSAGE_IDS,
            originalSeenIds)
            .then(function() {
              $rootScope.$emit('notificationChange');
              return originalSeenIds;
            })
            .catch(function(error) {
              $log.warn('Problem setting seen message IDs in storage');
              return error;
            });
        };

        /**
         * Notify listeners that priority notifications flag has changed
         * @param {boolean} hasNotifications
         */
        var broadcastPriorityFlag = function(hasNotifications) {
          $rootScope.$broadcast('HAS_PRIORITY_NOTIFICATIONS',
            {hasNotifications: hasNotifications}
          );

          // Update storage
          $localStorage.hasPriorityNotifications = hasNotifications;
        };

        return {
          getAllMessages: getAllMessages,
          getMessagesByGroup: getMessagesByGroup,
          getMessagesByData: getMessagesByData,
          getSeenMessageIds: getSeenMessageIds,
          setMessagesSeen: setMessagesSeen,
          broadcastPriorityFlag: broadcastPriorityFlag,
        };
    }]);
});
<|endoftext|>


<commit_before>'use strict'

const { Router } = require('express')
const router = Router()

const session = require('../controllers/session')
const wishlist = require('../controllers/wishlist')

router.post('/register', session.register)

router.post('/login', session.login)

router.post('/api/addToWishlist', wishlist.addToWishlist)

module.exports = router<commit_msg>added get wishlist route to routes index<commit_after>'use strict'

const { Router } = require('express')
const router = Router()

const session = require('../controllers/session')
const wishlist = require('../controllers/wishlist')

router.post('/register', session.register)

router.post('/login', session.login)

router.post('/api/addToWishlist', wishlist.addToWishlist)

router.get('/api/getWishlist', wishlist.getWishlist)

module.exports = router<|endoftext|>


<commit_before>'use strict'

const { Router } = require('express')
const router = Router()

const session = require('../controllers/session')
const wishlist = require('../controllers/wishlist')
const currentlyReading = require('../controllers/currently_reading')
const completed = require('../controllers/completed')

router.post('/register', session.register)

router.post('/login', session.login)

router.post('/api/addToWishlist', wishlist.addToWishlist)

router.post('/api/removeFromWishlist', wishlist.removeFromWishlist)

router.get('/api/getWishlist', wishlist.getWishlist)

router.post('/api/addToCurrentlyReading', currentlyReading.addToCurrentlyReading)

router.post('/api/removeFromCurrentlyReading', currentlyReading.removeFromCurrentlyReading)

router.get('/api/getCurrentlyReading', currentlyReading.getCurrentlyReading)

router.post('/api/addToCompleted', completed.addToCompleted)

router.post('/api/removeFromCompleted', completed.removeFromCompleted)

router.get('/api/getCompleted', completed.getCompleted)

module.exports = router<commit_msg>added get user and logout routes to index.js<commit_after>'use strict'

const { Router } = require('express')
const router = Router()

const session = require('../controllers/session')
const wishlist = require('../controllers/wishlist')
const currentlyReading = require('../controllers/currently_reading')
const completed = require('../controllers/completed')

router.post('/register', session.register)

router.post('/login', session.login)

router.get('/getUser', session.getUser)

router.post('/logout', session.logout)

router.post('/api/addToWishlist', wishlist.addToWishlist)

router.post('/api/removeFromWishlist', wishlist.removeFromWishlist)

router.get('/api/getWishlist', wishlist.getWishlist)

router.post('/api/addToCurrentlyReading', currentlyReading.addToCurrentlyReading)

router.post('/api/removeFromCurrentlyReading', currentlyReading.removeFromCurrentlyReading)

router.get('/api/getCurrentlyReading', currentlyReading.getCurrentlyReading)

router.post('/api/addToCompleted', completed.addToCompleted)

router.post('/api/removeFromCompleted', completed.removeFromCompleted)

router.get('/api/getCompleted', completed.getCompleted)

module.exports = router<|endoftext|>


<commit_before>COMPONENT.UIWidgetList = class extends COMPONENT.UIWidget {
    static config() {
        return {
            platform: "browser",
            tag: "widget-list"
        };
    }
    constructor(element) {
        super(element);
    }
    styles(element) {
        const isDefault = element.getAttribute("default");
        return {
            "background-color": isDefault ? "white" : "lightgray",
            display: "flex",
            "flex-direction": "row",
            "align-items": "center",
            "align-content": "center",
            "justify-content": "center",
            padding: "3px",
            "border-radius": "6px",
            ...this.region
        };
    }
    groups() {
        return {
            ...super.groups(),
            itemsClass: ".items"
        };
    }
    itemsClass() {
        return {
            "border": "1px solid darkgray",
            "overflow": "scroll",
            "max-height": "150px",
            "padding": "6px",
            "padding-right": "16px",
            "border-radius": "6px",
            "display": "flex",
            "flex-direction": "column"
        };
    }
    async move(pos) {
        if (pos) {
            let region = Object.assign({}, this.region);
            region.left = pos.left + "px";
            region.top = pos.top + "px";
            region.right = "";
            region.bottom = "";
            this.region = region;
            await this.updateStyles();
        }
    }
    render(element) {
        return "<widget-list-handle></widget-list-handle>
<slot></slot>
";
    }
};

COMPONENT.UIWidgetListHandle = class extends COMPONENT.UIWidget {
    static config() {
        return {
            platform: "browser",
            tag: "widget-list-handle"
        };
    }
    constructor(parent) {
        super(parent);
        this.move = this.attach(COMPONENT.UIWidgetListMove);
    }
    hover() {
        return {
            filter: "invert(50%)"
        };
    }
    touch() {
        return {
            filter: "invert(25%)"
        };
    }
    normal(element) {
        return {
            "background": "url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjwhRE9DVFlQRSBzdmcgIFBVQkxJQyAnLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4nICAnaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkJz48c3ZnIGhlaWdodD0iNTEycHgiIGlkPSJMYXllcl8xIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA1MTIgNTEyOyIgdmVyc2lvbj0iMS4xIiB2aWV3Qm94PSIwIDAgNTEyIDUxMiIgd2lkdGg9IjUxMnB4IiB4bWw6c3BhY2U9InByZXNlcnZlIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIj48Zz48Zz48cGF0aCBkPSJNMTYwLDE1My4zYzAsMy43LTMsNi43LTYuNyw2LjdoLTUwLjVjLTMuNywwLTYuNy0zLTYuNy02Ljd2LTUwLjVjMC0zLjcsMy02LjcsNi43LTYuN2g1MC41YzMuNywwLDYuNywzLDYuNyw2LjdWMTUzLjN6Ii8+PHBhdGggZD0iTTI4OCwxNTMuM2MwLDMuNy0zLDYuNy02LjcsNi43aC01MC41Yy0zLjcsMC02LjctMy02LjctNi43di01MC41YzAtMy43LDMtNi43LDYuNy02LjdoNTAuNWMzLjcsMCw2LjcsMyw2LjcsNi43VjE1My4zeiIvPjxwYXRoIGQ9Ik00MTYsMTUzLjNjMCwzLjctMyw2LjctNi43LDYuN2gtNTAuNWMtMy43LDAtNi43LTMtNi43LTYuN3YtNTAuNWMwLTMuNywzLTYuNyw2LjctNi43aDUwLjVjMy43LDAsNi43LDMsNi43LDYuN1YxNTMuM3oiLz48L2c+PGc+PHBhdGggZD0iTTE2MCwyODEuM2MwLDMuNy0zLDYuNy02LjcsNi43aC01MC41Yy0zLjcsMC02LjctMy02LjctNi43di01MC41YzAtMy43LDMtNi43LDYuNy02LjdoNTAuNWMzLjcsMCw2LjcsMyw2LjcsNi43VjI4MS4zeiIvPjxwYXRoIGQ9Ik0yODgsMjgxLjNjMCwzLjctMyw2LjctNi43LDYuN2gtNTAuNWMtMy43LDAtNi43LTMtNi43LTYuN3YtNTAuNWMwLTMuNywzLTYuNyw2LjctNi43aDUwLjVjMy43LDAsNi43LDMsNi43LDYuN1YyODEuM3oiLz48cGF0aCBkPSJNNDE2LDI4MS4zYzAsMy43LTMsNi43LTYuNyw2LjdoLTUwLjVjLTMuNywwLTYuNy0zLTYuNy02Ljd2LTUwLjVjMC0zLjcsMy02LjcsNi43LTYuN2g1MC41YzMuNywwLDYuNywzLDYuNyw2LjdWMjgxLjN6Ii8+PC9nPjxnPjxwYXRoIGQ9Ik0xNjAsNDA5LjNjMCwzLjctMyw2LjctNi43LDYuN2gtNTAuNWMtMy43LDAtNi43LTMtNi43LTYuN3YtNTAuNWMwLTMuNywzLTYuNyw2LjctNi43aDUwLjVjMy43LDAsNi43LDMsNi43LDYuN1Y0MDkuM3oiLz48cGF0aCBkPSJNMjg4LDQwOS4zYzAsMy43LTMsNi43LTYuNyw2LjdoLTUwLjVjLTMuNywwLTYuNy0zLTYuNy02Ljd2LTUwLjVjMC0zLjcsMy02LjcsNi43LTYuN2g1MC41YzMuNywwLDYuNywzLDYuNyw2LjdWNDA5LjN6Ii8+PHBhdGggZD0iTTQxNiw0MDkuM2MwLDMuNy0zLDYuNy02LjcsNi43aC01MC41Yy0zLjcsMC02LjctMy02LjctNi43di01MC41YzAtMy43LDMtNi43LDYuNy02LjdoNTAuNWMzLjcsMCw2LjcsMyw2LjcsNi43VjQwOS4zeiIvPjwvZz48L2c+PC9zdmc+') no-repeat",
            "background-size": "16px 16px",
            width: "16px",
            height: "16px",
            "border-radius": "6px",
            filter: "invert(75%)"
        };
    }
};

COMPONENT.UIWidgetListMove = class extends COMPONENT.UIEventMove {
    static config() {
        return {
            platform: "browser"
        };
    }
    owner() {
        return "widget-list";
    }
};

COMPONENT.UIWidgetListItem = class extends COMPONENT.UIWidget {
    static config() {
        return {
            platform: "browser",
            tag: "widget-list-item"
        };
    }
    members() {
        let children = Array.from(this.element.children);
        children = children.filter(child => child.tagName && child.tagName.toLowerCase() === "widget-list-item");
        return children;
    }
    isExpanded() {
        let children = this.members();
        let isExpanded = children.some(child => child.style.display !== "none");
        return isExpanded;
    }
    hasChildren() {
        return this.members().length;
    }
    normal(element) {
        return {
            "border-radius": "6px",
            "padding": "3px",
            "display": "block",
            "user-select": "none",
            "padding-left": "16px"
        };
    }
    render() {
        let html = "<widget-list-item-expand></widget-list-item-expand><slot></slot>";
        return html;
    }
};

COMPONENT.UIWidgetListItemExpand = class extends COMPONENT.UIWidget {
    static config() {
        return {
            platform: "browser",
            tag: "widget-list-item-expand"
        };
    }
    hover() {
        return {
            filter: "invert(20%)",
            "background-color": "white"
        };
    }
    touch() {
        return {
            filter: "invert(10%)"
        };
    }
    events() {
        return {
            click() {
                let children = this.instance.state("members");
                let isExpanded = this.instance.state("isExpanded");
                for (let child of children) {
                    if (!isExpanded) {
                        child.style.display = "block";
                    }
                    else {
                        child.style.display = "none";
                    }
                }
                this.instance.update();
            }
        };
    }
    normal(element) {
        let isExpanded = this.state("isExpanded");
        let hasChildren = this.state("hasChildren");
        return {
            "border-radius": "6px",
            "user-select": "none",
            "padding-left": "10px",
            "padding-right": "6px",
            "margin-right": "3px",
            "border": "1px solid lightgray",
            "width": "16px",
            "height": "16px",
            "visibility": hasChildren ? "visible" : "hidden",
            ...!isExpanded && { "background": "url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjwhRE9DVFlQRSBzdmcgIFBVQkxJQyAnLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4nICAnaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkJz48c3ZnIGhlaWdodD0iNTEycHgiIGlkPSJMYXllcl8xIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA1MTIgNTEyOyIgdmVyc2lvbj0iMS4xIiB2aWV3Qm94PSIwIDAgNTEyIDUxMiIgd2lkdGg9IjUxMnB4IiB4bWw6c3BhY2U9InByZXNlcnZlIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIj48cGF0aCBkPSJNMTg0LjcsNDEzLjFsMi4xLTEuOGwxNTYuNS0xMzZjNS4zLTQuNiw4LjYtMTEuNSw4LjYtMTkuMmMwLTcuNy0zLjQtMTQuNi04LjYtMTkuMkwxODcuMSwxMDFsLTIuNi0yLjMgIEMxODIsOTcsMTc5LDk2LDE3NS44LDk2Yy04LjcsMC0xNS44LDcuNC0xNS44LDE2LjZoMHYyODYuOGgwYzAsOS4yLDcuMSwxNi42LDE1LjgsMTYuNkMxNzkuMSw0MTYsMTgyLjIsNDE0LjksMTg0LjcsNDEzLjF6Ii8+PC9zdmc+) no-repeat" },
            ...isExpanded && { "background": "url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjwhRE9DVFlQRSBzdmcgIFBVQkxJQyAnLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4nICAnaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkJz48c3ZnIGhlaWdodD0iNTEycHgiIGlkPSJMYXllcl8xIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA1MTIgNTEyOyIgdmVyc2lvbj0iMS4xIiB2aWV3Qm94PSIwIDAgNTEyIDUxMiIgd2lkdGg9IjUxMnB4IiB4bWw6c3BhY2U9InByZXNlcnZlIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIj48cGF0aCBkPSJNOTguOSwxODQuN2wxLjgsMi4xbDEzNiwxNTYuNWM0LjYsNS4zLDExLjUsOC42LDE5LjIsOC42YzcuNywwLDE0LjYtMy40LDE5LjItOC42TDQxMSwxODcuMWwyLjMtMi42ICBjMS43LTIuNSwyLjctNS41LDIuNy04LjdjMC04LjctNy40LTE1LjgtMTYuNi0xNS44djBIMTEyLjZ2MGMtOS4yLDAtMTYuNiw3LjEtMTYuNiwxNS44Qzk2LDE3OS4xLDk3LjEsMTgyLjIsOTguOSwxODQuN3oiLz48L3N2Zz4=) no-repeat" },
            "background-size": "16px 16px",
        };
    }
};
<commit_msg>bug fix<commit_after>COMPONENT.UIWidgetList = class extends COMPONENT.UIWidget {
    static config() {
        return {
            platform: "browser",
            tag: "widget-list"
        };
    }
    constructor(element) {
        super(element);
    }
    styles(element) {
        const isDefault = element.getAttribute("default");
        return {
            "background-color": isDefault ? "white" : "lightgray",
            display: "flex",
            "flex-direction": "row",
            "align-items": "center",
            "align-content": "center",
            "justify-content": "center",
            padding: "3px",
            "border-radius": "6px",
            ...this.region
        };
    }
    groups() {
        return {
            ...super.groups(),
            itemsClass: ".items"
        };
    }
    itemsClass() {
        return {
            "border": "1px solid darkgray",
            "overflow": "scroll",
            "max-height": "150px",
            "padding": "6px",
            "padding-right": "16px",
            "border-radius": "6px",
            "display": "flex",
            "flex-direction": "column"
        };
    }
    async move(pos) {
        if (pos) {
            let region = Object.assign({}, this.region);
            region.left = pos.left + "px";
            region.top = pos.top + "px";
            region.right = "";
            region.bottom = "";
            this.region = region;
            await this.updateStyles();
        }
    }
    render(element) {
        return "<widget-list-handle></widget-list-handle>
<slot></slot>
";
    }
};

COMPONENT.UIWidgetListHandle = class extends COMPONENT.UIWidget {
    static config() {
        return {
            platform: "browser",
            tag: "widget-list-handle"
        };
    }
    constructor(parent) {
        super(parent);
        this.move = this.attach(COMPONENT.UIWidgetListMove);
    }
    hover() {
        return {
            filter: "invert(50%)"
        };
    }
    touch() {
        return {
            filter: "invert(25%)"
        };
    }
    normal(element) {
        return {
            "background": "url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjwhRE9DVFlQRSBzdmcgIFBVQkxJQyAnLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4nICAnaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkJz48c3ZnIGhlaWdodD0iNTEycHgiIGlkPSJMYXllcl8xIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA1MTIgNTEyOyIgdmVyc2lvbj0iMS4xIiB2aWV3Qm94PSIwIDAgNTEyIDUxMiIgd2lkdGg9IjUxMnB4IiB4bWw6c3BhY2U9InByZXNlcnZlIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIj48Zz48Zz48cGF0aCBkPSJNMTYwLDE1My4zYzAsMy43LTMsNi43LTYuNyw2LjdoLTUwLjVjLTMuNywwLTYuNy0zLTYuNy02Ljd2LTUwLjVjMC0zLjcsMy02LjcsNi43LTYuN2g1MC41YzMuNywwLDYuNywzLDYuNyw2LjdWMTUzLjN6Ii8+PHBhdGggZD0iTTI4OCwxNTMuM2MwLDMuNy0zLDYuNy02LjcsNi43aC01MC41Yy0zLjcsMC02LjctMy02LjctNi43di01MC41YzAtMy43LDMtNi43LDYuNy02LjdoNTAuNWMzLjcsMCw2LjcsMyw2LjcsNi43VjE1My4zeiIvPjxwYXRoIGQ9Ik00MTYsMTUzLjNjMCwzLjctMyw2LjctNi43LDYuN2gtNTAuNWMtMy43LDAtNi43LTMtNi43LTYuN3YtNTAuNWMwLTMuNywzLTYuNyw2LjctNi43aDUwLjVjMy43LDAsNi43LDMsNi43LDYuN1YxNTMuM3oiLz48L2c+PGc+PHBhdGggZD0iTTE2MCwyODEuM2MwLDMuNy0zLDYuNy02LjcsNi43aC01MC41Yy0zLjcsMC02LjctMy02LjctNi43di01MC41YzAtMy43LDMtNi43LDYuNy02LjdoNTAuNWMzLjcsMCw2LjcsMyw2LjcsNi43VjI4MS4zeiIvPjxwYXRoIGQ9Ik0yODgsMjgxLjNjMCwzLjctMyw2LjctNi43LDYuN2gtNTAuNWMtMy43LDAtNi43LTMtNi43LTYuN3YtNTAuNWMwLTMuNywzLTYuNyw2LjctNi43aDUwLjVjMy43LDAsNi43LDMsNi43LDYuN1YyODEuM3oiLz48cGF0aCBkPSJNNDE2LDI4MS4zYzAsMy43LTMsNi43LTYuNyw2LjdoLTUwLjVjLTMuNywwLTYuNy0zLTYuNy02Ljd2LTUwLjVjMC0zLjcsMy02LjcsNi43LTYuN2g1MC41YzMuNywwLDYuNywzLDYuNyw2LjdWMjgxLjN6Ii8+PC9nPjxnPjxwYXRoIGQ9Ik0xNjAsNDA5LjNjMCwzLjctMyw2LjctNi43LDYuN2gtNTAuNWMtMy43LDAtNi43LTMtNi43LTYuN3YtNTAuNWMwLTMuNywzLTYuNyw2LjctNi43aDUwLjVjMy43LDAsNi43LDMsNi43LDYuN1Y0MDkuM3oiLz48cGF0aCBkPSJNMjg4LDQwOS4zYzAsMy43LTMsNi43LTYuNyw2LjdoLTUwLjVjLTMuNywwLTYuNy0zLTYuNy02Ljd2LTUwLjVjMC0zLjcsMy02LjcsNi43LTYuN2g1MC41YzMuNywwLDYuNywzLDYuNyw2LjdWNDA5LjN6Ii8+PHBhdGggZD0iTTQxNiw0MDkuM2MwLDMuNy0zLDYuNy02LjcsNi43aC01MC41Yy0zLjcsMC02LjctMy02LjctNi43di01MC41YzAtMy43LDMtNi43LDYuNy02LjdoNTAuNWMzLjcsMCw2LjcsMyw2LjcsNi43VjQwOS4zeiIvPjwvZz48L2c+PC9zdmc+') no-repeat",
            "background-size": "16px 16px",
            width: "16px",
            height: "16px",
            "border-radius": "6px",
            filter: "invert(75%)"
        };
    }
};

COMPONENT.UIWidgetListMove = class extends COMPONENT.UIEventMove {
    static config() {
        return {
            platform: "browser"
        };
    }
    owner() {
        return "widget-list";
    }
};

COMPONENT.UIWidgetListItem = class extends COMPONENT.UIWidget {
    static config() {
        return {
            platform: "browser",
            tag: "widget-list-item"
        };
    }
    members() {
        let children = Array.from(this.element.children);
        children = children.filter(child => child.tagName && child.tagName.toLowerCase() === "widget-list-item");
        return children;
    }
    isExpanded() {
        let children = this.members();
        let isExpanded = children.some(child => child.style.display !== "none");
        return isExpanded;
    }
    hasParent() {
        return this.parent("widget-list-item");
    }
    hasChildren() {
        return this.members().length;
    }
    normal(element) {
        return {
            "border-radius": "6px",
            "padding": "3px",
            "display": "block",
            "user-select": "none",
            ... this.hasParent() && { "padding-left": "16px" }
        };
    }
    render() {
        let html = "<widget-list-item-expand></widget-list-item-expand><slot></slot>";
        return html;
    }
};

COMPONENT.UIWidgetListItemExpand = class extends COMPONENT.UIWidget {
    static config() {
        return {
            platform: "browser",
            tag: "widget-list-item-expand"
        };
    }
    hover() {
        return {
            filter: "invert(20%)",
            "background-color": "white"
        };
    }
    touch() {
        return {
            filter: "invert(10%)"
        };
    }
    events() {
        return {
            click() {
                let children = this.instance.state("members");
                let isExpanded = this.instance.state("isExpanded");
                for (let child of children) {
                    if (!isExpanded) {
                        child.style.display = "block";
                    }
                    else {
                        child.style.display = "none";
                    }
                }
                this.instance.update();
            }
        };
    }
    normal(element) {
        let isExpanded = this.state("isExpanded");
        let hasChildren = this.state("hasChildren");
        return {
            "border-radius": "6px",
            "user-select": "none",
            "padding-left": "10px",
            "padding-right": "6px",
            "margin-right": "3px",
            "border": "1px solid lightgray",
            "width": "16px",
            "height": "16px",
            "visibility": hasChildren ? "visible" : "hidden",
            ...!isExpanded && { "background": "url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjwhRE9DVFlQRSBzdmcgIFBVQkxJQyAnLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4nICAnaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkJz48c3ZnIGhlaWdodD0iNTEycHgiIGlkPSJMYXllcl8xIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA1MTIgNTEyOyIgdmVyc2lvbj0iMS4xIiB2aWV3Qm94PSIwIDAgNTEyIDUxMiIgd2lkdGg9IjUxMnB4IiB4bWw6c3BhY2U9InByZXNlcnZlIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIj48cGF0aCBkPSJNMTg0LjcsNDEzLjFsMi4xLTEuOGwxNTYuNS0xMzZjNS4zLTQuNiw4LjYtMTEuNSw4LjYtMTkuMmMwLTcuNy0zLjQtMTQuNi04LjYtMTkuMkwxODcuMSwxMDFsLTIuNi0yLjMgIEMxODIsOTcsMTc5LDk2LDE3NS44LDk2Yy04LjcsMC0xNS44LDcuNC0xNS44LDE2LjZoMHYyODYuOGgwYzAsOS4yLDcuMSwxNi42LDE1LjgsMTYuNkMxNzkuMSw0MTYsMTgyLjIsNDE0LjksMTg0LjcsNDEzLjF6Ii8+PC9zdmc+) no-repeat" },
            ...isExpanded && { "background": "url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjwhRE9DVFlQRSBzdmcgIFBVQkxJQyAnLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4nICAnaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkJz48c3ZnIGhlaWdodD0iNTEycHgiIGlkPSJMYXllcl8xIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA1MTIgNTEyOyIgdmVyc2lvbj0iMS4xIiB2aWV3Qm94PSIwIDAgNTEyIDUxMiIgd2lkdGg9IjUxMnB4IiB4bWw6c3BhY2U9InByZXNlcnZlIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIj48cGF0aCBkPSJNOTguOSwxODQuN2wxLjgsMi4xbDEzNiwxNTYuNWM0LjYsNS4zLDExLjUsOC42LDE5LjIsOC42YzcuNywwLDE0LjYtMy40LDE5LjItOC42TDQxMSwxODcuMWwyLjMtMi42ICBjMS43LTIuNSwyLjctNS41LDIuNy04LjdjMC04LjctNy40LTE1LjgtMTYuNi0xNS44djBIMTEyLjZ2MGMtOS4yLDAtMTYuNiw3LjEtMTYuNiwxNS44Qzk2LDE3OS4xLDk3LjEsMTgyLjIsOTguOSwxODQuN3oiLz48L3N2Zz4=) no-repeat" },
            "background-size": "16px 16px",
        };
    }
};
<|endoftext|>


<commit_before>var express = require('express');
var router = express.Router();
var csrf = require('csurf');
var passport = require('passport');

var csrfProtection = csrf();
router.use(csrfProtection);

router.route('/signup')
    .get(function(req, res) {
        res.render('user/signup', {
            pageId: "Signup",
            pageTitle: "Sign up",
            pageDescription: "Home Control's sign up page.",
            pageCss: ['main'],
            pageScripts: [],
            useBootstrap: true,
            csrfToken: req.csrfToken(),
            error: req.flash('error')
        })
    }).post(passport.authenticate('local.signup', {
        successRedirect: '/viewer',
        failureRedirect:'/user/signup',
        failureFlash: true
    }));

router.route('/login')
    .get(function (req, res) {
        res.render('user/login', {
            pageId: "Login",
            pageTitle: "Log in",
            pageDescription: "Home Control's log in page.",
            pageCss: ['main'],
            pageScripts: [],
            useBootstrap: true,
            csrfToken: req.csrfToken(),
            error: req.flash('error')
        });
    }).post(passport.authenticate('local.login', {
        successRedirect: '/viewer',
        failureRedirect:'/user/login',
        failureFlash: true
    }));

router.route('/logout')
    .get(function(req, res) {
        req.logout();
        res.redirect('/');
    });

module.exports = router;<commit_msg>Redirect from login to devices on success<commit_after>var express = require('express');
var router = express.Router();
var csrf = require('csurf');
var passport = require('passport');

var csrfProtection = csrf();
router.use(csrfProtection);

router.route('/signup')
    .get(function(req, res) {
        res.render('user/signup', {
            pageId: "Signup",
            pageTitle: "Sign up",
            pageDescription: "Home Control's sign up page.",
            pageCss: ['main'],
            pageScripts: [],
            useBootstrap: true,
            csrfToken: req.csrfToken(),
            error: req.flash('error')
        })
    }).post(passport.authenticate('local.signup', {
        successRedirect: '/viewer',
        failureRedirect:'/user/signup',
        failureFlash: true
    }));

router.route('/login')
    .get(function (req, res) {
        res.render('user/login', {
            pageId: "Login",
            pageTitle: "Log in",
            pageDescription: "Home Control's log in page.",
            pageCss: ['main'],
            pageScripts: [],
            useBootstrap: true,
            csrfToken: req.csrfToken(),
            error: req.flash('error')
        });
    }).post(passport.authenticate('local.login', {
        successRedirect: '/device',
        failureRedirect:'/user/login',
        failureFlash: true
    }));

router.route('/logout')
    .get(function(req, res) {
        req.logout();
        res.redirect('/');
    });

module.exports = router;<|endoftext|>