<commit_before>import Vector2 from '../vector2'
// TODO: don't use this directly, refer to it from game so this is completely separate
import {Time} from '../constants/private'

// https://www.geometrictools.com/Documentation/MethodOfSeparatingAxes.pdf
// See section on "moving objects"

// if it overlaps, return the projection vector
function checkProjectionOverlap(vertices1, vertices2, vector, MTV) {
  let min1 = Infinity
  let max1 = -Infinity
  let min2 = Infinity
  let max2 = -Infinity
  vertices1.map(function(vertex) {
    let val = Vector2.ProjectScalar(vertex, vector)
    min1 = Math.min(min1, val)
    max1 = Math.max(max1, val)
  })

  vertices2.map(function(vertex) {
    let val = Vector2.ProjectScalar(vertex, vector)
    min2 = Math.min(min2, val)
    max2 = Math.max(max2, val)
  })

  // no overlap
  if (min1 > max2 || max1 < min2) {
    return null
  } else {
    // the magnitude of the overlap
    let newMTVMagnitude = Math.min(max2 - min1, max1 - min2)
    let vectorMag = vector.mag()
    // if the magnitude is smaller than the magnitude of the current mtv then we should update
    // the mtv with the new values
    if (newMTVMagnitude < MTV.mag()) {
      MTV.x = vector.x * newMTVMagnitude / vectorMag
      MTV.y = vector.y * newMTVMagnitude / vectorMag
    }
    return MTV
  }
}

// TODO: for now it assumes both gobs are convex
// returns null if no collision, otherwise returns MTV
// http://www.metanetsoftware.com/technique/tutorialA.html
export function SAT(gob1, gob2) {
  // get the absolute vertices
  let vertices1 = gob1.getAABB()
  let vertices2 = gob2.getAABB()

  // gather the normals
  let normals1 = gob1.getNormals()
  let normals2 = gob2.getNormals()

  let MTV = new Vector2(-Infinity, -Infinity)

  // for each normal, project both shapes onto the normal. if they don't intersect, then immediately return false.
  // otherwise return true at the end
  for (let i=0; i<normals1.length; i++) {
    MTV = checkProjectionOverlap(vertices1, vertices2, normals1[i], MTV)
    if (MTV == null) {
      return false
    }
  }

  for (let i=0; i<normals2.length; i++) {
    MTV = checkProjectionOverlap(vertices1, vertices2, normals2[i], MTV)
    if (MTV == null) {
      return false
    }
  }

  // TODO: adjust the gobs here instead of in collision engine
  resolveStaticCollision(gob1, gob2, MTV)

  return true
}

/* resolve a collision between two non-moving objects (project them out) */
export function resolveStaticCollision(gob1, gob2, MTV) {
  // first project gob1 and gob2 out of the MTV by determining the proportion of VELOCITY
  let v1m = gob1.velocity.mag()
  let v2m = gob2.velocity.mag()

  let totalVelocity = v1m + v2m

  let p1 = v1m / (v1m + v2m)
  let p2 = v2m / (v2m + v1m)

  let [left, right] = gob1.position.x >= gob2.position.x ? [gob2, gob1] : [gob1, gob2]
  let [top, bottom] = gob1.position.y >= gob2.position.y ? [gob2, gob1] : [gob1, gob2]

  right.position.x += MTV.x
  bottom.position.y -= MTV.y
}

// TODO: Have restitution ONLY BE APPLIED for normal velocities
// ALSO TODO: Have restitution be applied PER OBJEcT. It's just easier to
// think about that way. if you don't want an object to have energy lost in
// collistion, just set the mass to 0!
// http://vobarian.com/collisions/2dcollisions2.pdf
function adjustPhysicsVelocity(gob1, gob2, normal) {
  // tangent is the normal of the normal
  const tangent = normal.orthol()
  // const unitNormal = Vector2.Normalized(normal)

  const unitNormal = Vector2.Normalized(normal)
  const unitTangent = Vector2.Normalized(tangent)

  const m1 = gob1.mass
  const m2 = gob2.mass

  const v1n = Vector2.ProjectScalar(gob1.velocity, normal)
  const v1t = Vector2.ProjectScalar(gob1.velocity, tangent)
  const v2n = Vector2.ProjectScalar(gob2.velocity, normal)
  const v2t = Vector2.ProjectScalar(gob2.velocity, tangent)

  // coefficient of restitution == bounciness
  // See http://www.box2dflash.org/docs/2.0.2/manual#Friction_and_Restitution
  // const restitution = Math.max(gob1.bounce, gob2.bounce)
  //
  // Instead of having a single restitution value, we just use restitution
  // per object. this way, dev's can more easily imagine how individual objects
  // are affected by collisions
  //
  // (v1n * (m1 - m2) + 2 * m2 * v2n) / (m1 + m2)
  const newv1n = gob1.bounce * (v1n * (m1 - m2) + 2 * m2 * v2n) / (m1 + m2)
  const newv1t = v1t

  // coefficient of restitution == bounciness
  // (v2n * (m2 - m1) + 2 * m1 * v1n) / (m1 + m2)
  const newv2n = gob2.bounce * (v2n * (m2 - m1) + 2 * m1 * v1n) / (m1 + m2)
  const newv2t = v2t

  // find the new velocity normals
  const newVelocityNormal1 = Vector2.Multiply(unitNormal, newv1n)
  const newVelocityNormal2 = Vector2.Multiply(unitNormal, newv2n)

  const newVelocityTangent1 = Vector2.Multiply(unitTangent, newv1t)
  const newVelocityTangent2 = Vector2.Multiply(unitTangent, newv2t)

  const newVelocity1 = Vector2.Add(newVelocityNormal1, newVelocityTangent1)
  const newVelocity2 = Vector2.Add(newVelocityNormal2, newVelocityTangent2)

  gob1.velocity.x = newVelocity1.x
  gob1.velocity.y = newVelocity1.y
  gob2.velocity.x = newVelocity2.x
  gob2.velocity.y = newVelocity2.y
}

// https://www.geometrictools.com/Documentation/MethodOfSeparatingAxes.pdf
export function movingSAT(gob1, gob2) {
  // get the absolute vertices
  let vertices1 = gob1.getAABB()
  let vertices2 = gob2.getAABB()

  // velocity
  const velocity = Vector2.Subtract(gob2._velocity, gob1._velocity)

  // gather the normals
  let normals = gob1.getNormals().concat(gob2.getNormals())

  let MTV = new Vector2(-Infinity, -Infinity)

  // we are calculating in terms of a single timestep
  let TMax = Time.dts
  let TFirst = 0
  let TLast = Infinity

  let Length = 0

  // if there has been a collision, calculate how far it's gone
  let TElapsed = 0
  let edge1
  let edge2
  let normal

  // for each normal, project both shapes onto the normal.
  // if they don't intersect, then immediately return false.
  // otherwise return true at the end
  for (let i=0; i<normals.length; i++) {
    // speed is the projection of the speed onto the normal
    const speed = Vector2.ProjectScalar(velocity, normals[i])
    let T

    let min0 = Infinity
    let max0 = -Infinity
    let min1 = Infinity
    let max1 = -Infinity

    let min0Index = Infinity
    let max0Index = -Infinity
    let min1Index = Infinity
    let max1Index = -Infinity

    // get max and min of collision
    vertices1.map(function(vertex, index) {
      let val = Vector2.ProjectScalar(vertex, normals[i])
      min0 = Math.min(min0, val)
      if (val > max0) {
        max0 = val
        max0Index = index
      }
    })

    vertices2.map(function(vertex, index) {
      let val = Vector2.ProjectScalar(vertex, normals[i])
      min1 = Math.min(min1, val)
      if (val > max1) {
        max1 = val
        max1Index = index
      }
    })

    if (max1 < min0) {
      if (speed <= 0) {
        return false
      }
      T = (min0 - max1) / speed
      if (T > TFirst) {
        TFirst = T
        Length = min0 - max1
        normal = normals[i]
      }
      if (TFirst > TMax) {
        return false
      }
      T = (max0 - min1) / speed
      if (T < TLast) {
        TLast = T
      }
      if (TFirst > TLast) {
        return false
      }
    } else if (max0 < min1) {
      if (speed >= 0) {
        return false
      }
      T = (max0 - min1) / speed
      if (T > TFirst) {
        TFirst = T
        Length = max0 - min1
        normal = normals[i]
      }
      if (TFirst > TMax) {
        return false
      }
      T = (min0 - max1) / speed
      if (T < TLast) {
        TLast = T
      }
      if (TFirst > TLast) {
        return false
      }
    } else {
      if (speed > 0) {
        T = (max0 - min1) / speed
        if (T < TLast) {
          TLast = T
        }
        if (TFirst > TLast) {
          return false
        }
      } else if (speed < 0) {
        T = (min0 - max1) / speed
        if (T < TLast) {
          TLast = T
        }
        if (TFirst > TLast) {
          return false
        }
      }
    }

    // set TElapsed
    // the minimum of the two possible overlaps, to determine actual overlap
    if (speed !== 0) {
      TElapsed = Math.min(Math.abs(max0 - min1), Math.abs(max1 - min0)) / Math.abs(speed)
    }
  }

  // collided! we limit the gob resolution to this method, to preserve modularity
  if (TFirst !== 0) {
    // it's going to collide with this next move. in this case, we need to
    // adjust so it doesn't overshoot.

    // TODO: THIS IS A HACK. we set it to be at TFirst - 0.0001 so that there
    // isn't going to be an overlap
    gob1.position.y = gob1._position.y + gob1._velocity.y  * (TFirst - 0.0001)
    gob1.position.x = gob1._position.x + gob1._velocity.x  * (TFirst - 0.0001)

    gob2.position.y = gob2._position.y + gob2._velocity.y  * (TFirst - 0.0001)
    gob2.position.x = gob2._position.x + gob2._velocity.x  * (TFirst - 0.0001)

    adjustPhysicsVelocity(gob1, gob2, normal)

    // TODO: a leftover of (Time.dts - (TFirst - 0.0001)) of new velocity for
    // each will be lost
  }

  return true
}
<commit_msg>add tangential friction<commit_after>import Vector2 from '../vector2'
// TODO: don't use this directly, refer to it from game so this is completely separate
import {Time} from '../constants/private'

// https://www.geometrictools.com/Documentation/MethodOfSeparatingAxes.pdf
// See section on "moving objects"

// if it overlaps, return the projection vector
function checkProjectionOverlap(vertices1, vertices2, vector, MTV) {
  let min1 = Infinity
  let max1 = -Infinity
  let min2 = Infinity
  let max2 = -Infinity
  vertices1.map(function(vertex) {
    let val = Vector2.ProjectScalar(vertex, vector)
    min1 = Math.min(min1, val)
    max1 = Math.max(max1, val)
  })

  vertices2.map(function(vertex) {
    let val = Vector2.ProjectScalar(vertex, vector)
    min2 = Math.min(min2, val)
    max2 = Math.max(max2, val)
  })

  // no overlap
  if (min1 > max2 || max1 < min2) {
    return null
  } else {
    // the magnitude of the overlap
    let newMTVMagnitude = Math.min(max2 - min1, max1 - min2)
    let vectorMag = vector.mag()
    // if the magnitude is smaller than the magnitude of the current mtv then we should update
    // the mtv with the new values
    if (newMTVMagnitude < MTV.mag()) {
      MTV.x = vector.x * newMTVMagnitude / vectorMag
      MTV.y = vector.y * newMTVMagnitude / vectorMag
    }
    return MTV
  }
}

// TODO: for now it assumes both gobs are convex
// returns null if no collision, otherwise returns MTV
// http://www.metanetsoftware.com/technique/tutorialA.html
export function SAT(gob1, gob2) {
  // get the absolute vertices
  let vertices1 = gob1.getAABB()
  let vertices2 = gob2.getAABB()

  // gather the normals
  let normals1 = gob1.getNormals()
  let normals2 = gob2.getNormals()

  let MTV = new Vector2(-Infinity, -Infinity)

  // for each normal, project both shapes onto the normal. if they don't intersect, then immediately return false.
  // otherwise return true at the end
  for (let i=0; i<normals1.length; i++) {
    MTV = checkProjectionOverlap(vertices1, vertices2, normals1[i], MTV)
    if (MTV == null) {
      return false
    }
  }

  for (let i=0; i<normals2.length; i++) {
    MTV = checkProjectionOverlap(vertices1, vertices2, normals2[i], MTV)
    if (MTV == null) {
      return false
    }
  }

  // TODO: adjust the gobs here instead of in collision engine
  resolveStaticCollision(gob1, gob2, MTV)

  return true
}

/* resolve a collision between two non-moving objects (project them out) */
export function resolveStaticCollision(gob1, gob2, MTV) {
  // first project gob1 and gob2 out of the MTV by determining the proportion of VELOCITY
  let v1m = gob1.velocity.mag()
  let v2m = gob2.velocity.mag()

  let totalVelocity = v1m + v2m

  let p1 = v1m / (v1m + v2m)
  let p2 = v2m / (v2m + v1m)

  let [left, right] = gob1.position.x >= gob2.position.x ? [gob2, gob1] : [gob1, gob2]
  let [top, bottom] = gob1.position.y >= gob2.position.y ? [gob2, gob1] : [gob1, gob2]

  right.position.x += MTV.x
  bottom.position.y -= MTV.y
}

// TODO: Have restitution ONLY BE APPLIED for normal velocities
// ALSO TODO: Have restitution be applied PER OBJEcT. It's just easier to
// think about that way. if you don't want an object to have energy lost in
// collistion, just set the mass to 0!
// http://vobarian.com/collisions/2dcollisions2.pdf
function adjustPhysicsVelocity(gob1, gob2, normal) {
  // tangent is the normal of the normal
  const tangent = normal.orthol()
  // const unitNormal = Vector2.Normalized(normal)

  const unitNormal = Vector2.Normalized(normal)
  const unitTangent = Vector2.Normalized(tangent)

  const m1 = gob1.mass
  const m2 = gob2.mass

  const v1n = Vector2.ProjectScalar(gob1.velocity, normal)
  const v1t = Vector2.ProjectScalar(gob1.velocity, tangent)
  const v2n = Vector2.ProjectScalar(gob2.velocity, normal)
  const v2t = Vector2.ProjectScalar(gob2.velocity, tangent)

  // coefficient of restitution == bounciness
  // See http://www.box2dflash.org/docs/2.0.2/manual#Friction_and_Restitution
  // const restitution = Math.max(gob1.bounce, gob2.bounce)
  //
  // Instead of having a single restitution value, we just use restitution
  // per object. this way, dev's can more easily imagine how individual objects
  // are affected by collisions
  //
  // (v1n * (m1 - m2) + 2 * m2 * v2n) / (m1 + m2)
  const newv1n = gob1.bounce * (v1n * (m1 - m2) + 2 * m2 * v2n) / (m1 + m2)
  // for tangent values, we need to adjust it according to the friction
  const newv1t = Math.max(0, 1 - gob1.friction) * v1t

  // coefficient of restitution == bounciness
  // (v2n * (m2 - m1) + 2 * m1 * v1n) / (m1 + m2)
  const newv2n = gob2.bounce * (v2n * (m2 - m1) + 2 * m1 * v1n) / (m1 + m2)
  const newv2t = Math.max(0, 1 - gob2.friction) * v2t

  // find the new velocity normals
  const newVelocityNormal1 = Vector2.Multiply(unitNormal, newv1n)
  const newVelocityNormal2 = Vector2.Multiply(unitNormal, newv2n)

  const newVelocityTangent1 = Vector2.Multiply(unitTangent, newv1t)
  const newVelocityTangent2 = Vector2.Multiply(unitTangent, newv2t)

  const newVelocity1 = Vector2.Add(newVelocityNormal1, newVelocityTangent1)
  const newVelocity2 = Vector2.Add(newVelocityNormal2, newVelocityTangent2)

  gob1.velocity.x = newVelocity1.x
  gob1.velocity.y = newVelocity1.y
  gob2.velocity.x = newVelocity2.x
  gob2.velocity.y = newVelocity2.y
}

// https://www.geometrictools.com/Documentation/MethodOfSeparatingAxes.pdf
export function movingSAT(gob1, gob2) {
  // get the absolute vertices
  let vertices1 = gob1.getAABB()
  let vertices2 = gob2.getAABB()

  // velocity
  const velocity = Vector2.Subtract(gob2._velocity, gob1._velocity)

  // gather the normals
  let normals = gob1.getNormals().concat(gob2.getNormals())

  let MTV = new Vector2(-Infinity, -Infinity)

  // we are calculating in terms of a single timestep
  let TMax = Time.dts
  let TFirst = 0
  let TLast = Infinity

  let Length = 0

  // if there has been a collision, calculate how far it's gone
  let TElapsed = 0
  let edge1
  let edge2
  let normal

  // for each normal, project both shapes onto the normal.
  // if they don't intersect, then immediately return false.
  // otherwise return true at the end
  for (let i=0; i<normals.length; i++) {
    // speed is the projection of the speed onto the normal
    const speed = Vector2.ProjectScalar(velocity, normals[i])
    let T

    let min0 = Infinity
    let max0 = -Infinity
    let min1 = Infinity
    let max1 = -Infinity

    let min0Index = Infinity
    let max0Index = -Infinity
    let min1Index = Infinity
    let max1Index = -Infinity

    // get max and min of collision
    vertices1.map(function(vertex, index) {
      let val = Vector2.ProjectScalar(vertex, normals[i])
      min0 = Math.min(min0, val)
      if (val > max0) {
        max0 = val
        max0Index = index
      }
    })

    vertices2.map(function(vertex, index) {
      let val = Vector2.ProjectScalar(vertex, normals[i])
      min1 = Math.min(min1, val)
      if (val > max1) {
        max1 = val
        max1Index = index
      }
    })

    if (max1 < min0) {
      if (speed <= 0) {
        return false
      }
      T = (min0 - max1) / speed
      if (T > TFirst) {
        TFirst = T
        Length = min0 - max1
        normal = normals[i]
      }
      if (TFirst > TMax) {
        return false
      }
      T = (max0 - min1) / speed
      if (T < TLast) {
        TLast = T
      }
      if (TFirst > TLast) {
        return false
      }
    } else if (max0 < min1) {
      if (speed >= 0) {
        return false
      }
      T = (max0 - min1) / speed
      if (T > TFirst) {
        TFirst = T
        Length = max0 - min1
        normal = normals[i]
      }
      if (TFirst > TMax) {
        return false
      }
      T = (min0 - max1) / speed
      if (T < TLast) {
        TLast = T
      }
      if (TFirst > TLast) {
        return false
      }
    } else {
      if (speed > 0) {
        T = (max0 - min1) / speed
        if (T < TLast) {
          TLast = T
        }
        if (TFirst > TLast) {
          return false
        }
      } else if (speed < 0) {
        T = (min0 - max1) / speed
        if (T < TLast) {
          TLast = T
        }
        if (TFirst > TLast) {
          return false
        }
      }
    }

    // set TElapsed
    // the minimum of the two possible overlaps, to determine actual overlap
    if (speed !== 0) {
      TElapsed = Math.min(Math.abs(max0 - min1), Math.abs(max1 - min0)) / Math.abs(speed)
    }
  }

  // collided! we limit the gob resolution to this method, to preserve modularity
  if (TFirst !== 0) {
    // it's going to collide with this next move. in this case, we need to
    // adjust so it doesn't overshoot.

    // TODO: THIS IS A HACK. we set it to be at TFirst - 0.0001 so that there
    // isn't going to be an overlap
    gob1.position.y = gob1._position.y + gob1._velocity.y  * (TFirst - 0.0001)
    gob1.position.x = gob1._position.x + gob1._velocity.x  * (TFirst - 0.0001)

    gob2.position.y = gob2._position.y + gob2._velocity.y  * (TFirst - 0.0001)
    gob2.position.x = gob2._position.x + gob2._velocity.x  * (TFirst - 0.0001)

    adjustPhysicsVelocity(gob1, gob2, normal)

    // TODO: a leftover of (Time.dts - (TFirst - 0.0001)) of new velocity for
    // each will be lost
  }

  return true
}
<|endoftext|>


<commit_before>var RomoTooltip = function(element) {
  this.elem = element;
  this.doInitPopup();

  this.hoverState = 'out';
  this.delayEnter = 0;
  this.delayLeave = 0;
  if (Romo.data(this.elem, 'romo-tooltip-delay') !== undefined && Romo.data(this.elem, 'romo-tooltip-delay') !== '') {
    this.delayEnter = Romo.data(this.elem, 'romo-tooltip-delay');
    this.delayLeave = Romo.data(this.elem, 'romo-tooltip-delay');
  }
  if (Romo.data(this.elem, 'romo-tooltip-delay-enter') !== undefined && Romo.data(this.elem, 'romo-tooltip-delay-enter') !== '') {
    this.delayEnter = Romo.data(this.elem, 'romo-tooltip-delay-enter');
  }
  if (Romo.data(this.elem, 'romo-tooltip-delay-leave') !== undefined && Romo.data(this.elem, 'romo-tooltip-delay-leave') !== '') {
    this.delayLeave = Romo.data(this.elem, 'romo-tooltip-delay-leave');
  }

  if (Romo.data(this.elem, 'romo-tooltip-style-class') !== undefined) {
    Romo.addClass(this.bodyElem, Romo.data(this.elem, 'romo-tooltip-style-class'));
  }

  Romo.on(this.elem, 'mouseenter', Romo.proxy(this.onToggleEnter, this));
  Romo.on(this.elem, 'mouseleave', Romo.proxy(this.onToggleLeave, this));
  Romo.on(this.elem, 'romoTooltip:triggerPopupOpen', Romo.proxy(this.onPopupOpen, this));
  Romo.on(this.elem, 'romoTooltip:triggerPopupClose', Romo.proxy(this.onPopupClose, this));
  Romo.on(this.elem, 'romoTooltip:triggerSetContent', Romo.proxy(this.onSetContent, this));
  Romo.on(window, 'resize', Romo.proxy(this.onResizeWindow, this))

  this.doInit();
  this.doInitBody();
  if (Romo.data(this.elem, 'romo-tooltip-content') === undefined) {
    this.doBindAjax();
  }

  Romo.trigger(this.elem, 'romoTooltip:ready', [this]);
}

RomoTooltip.prototype.doInit = function() {
  // override as needed
}

RomoTooltip.prototype.doInitPopup = function() {
  this.popupElem = Romo.elems('

')[0];
  var popupParentElem = Romo.closest(this.elem, Romo.data(this.elem, 'romo-tooltip-append-to-closest') || 'body');
  Romo.append(popupParentElem, this.popupElem);

  this.bodyElem = Romo.find(this.popupElem, '> .romo-tooltip-body')[0];

  this.popupPosition = Romo.data(this.elem, 'romo-tooltip-position') || 'top';
  Romo.setData(this.popupElem, 'romo-tooltip-position', this.popupPosition);

  this.popupAlignment = Romo.data(this.elem, 'romo-tooltip-alignment') || 'center';
  Romo.setData(this.popupElem, 'romo-tooltip-alignment', this.popupAlignment);

  this.doSetPopupZIndex(this.elem);

  // don't propagate click events on the popup elem.  this prevents the popup
  // from closing when clicked (see body click event bind on popup open)
  Romo.on(this.popupElem, 'click', function(e) {
    if (e !== undefined) {
      e.stopPropagation();
    }
  })

  // the popup should be treated like a child elem.  add it to Romo's
  // parent-child elems so it will be removed when the elem is removed.
  // delay adding it b/c other components may `append` generated tooltips
  // meaning the tooltip is removed and then re-added.  if added immediately
  // the "remove" part will incorrectly remove the popup.
  setTimeout(Romo.proxy(function() {
    Romo.parentChildElems.add(this.elem, [this.popupElem]);
  }, this), 1);
}

RomoTooltip.prototype.doInitBody = function() {
  this.doResetBody();

  Romo.setStyle(this.bodyElem, 'min-width',  Romo.data(this.elem, 'romo-tooltip-min-width'));
  Romo.setStyle(this.bodyElem, 'max-width',  Romo.data(this.elem, 'romo-tooltip-max-width'));
  Romo.setStyle(this.bodyElem, 'width',      Romo.data(this.elem, 'romo-tooltip-width'));
  Romo.setStyle(this.bodyElem, 'min-height', Romo.data(this.elem, 'romo-tooltip-min-height'));
  Romo.setStyle(this.bodyElem, 'height',     Romo.data(this.elem, 'romo-tooltip-height'));

  if (Romo.data(this.elem, 'romo-tooltip-max-height') === undefined) {
    Romo.setData(this.elem, 'romo-tooltip-max-height', 'detect');
  }
  if (Romo.data(this.elem, 'romo-tooltip-max-height') !== 'detect') {
    Romo.setStyle(this.bodyElem, 'max-height', Romo.data(this.elem, 'romo-tooltip-max-height'));
  }
}

RomoTooltip.prototype.doResetBody = function() {
  Romo.setStyle(this.bodyElem, 'min-width',  '');
  Romo.setStyle(this.bodyElem, 'max-width',  '');
  Romo.setStyle(this.bodyElem, 'width',      '');
  Romo.setStyle(this.bodyElem, 'min-height', '');
  Romo.setStyle(this.bodyElem, 'max-height', '');
  Romo.setStyle(this.bodyElem, 'height',     '');
}

RomoTooltip.prototype.doBindAjax = function() {
  this.romoAjax = new RomoAjax(this.elem);
  this.romoAjax.doUnbindElem(); // disable auto invoke on click

  Romo.on(this.elem, 'romoAjax:callStart', Romo.proxy(function(e, romoAjax) {
    this.doLoadBodyStart();
    return false;
  }, this));
  Romo.on(this.elem, 'romoAjax:callSuccess', Romo.proxy(function(e, data, romoAjax) {
    this.doLoadBodySuccess(data);
    return false;
  }, this));
  Romo.on(this.elem, 'romoAjax:callError', Romo.proxy(function(e, xhr, romoAjax) {
    this.doLoadBodyError(xhr);
    return false;
  }, this));
}

RomoTooltip.prototype.doLoadBodyStart = function() {
  this._setBodyHtml('');
  this.doInitBody();
  this.doPlacePopupElem();
  Romo.trigger(this.elem, 'romoTooltip:loadBodyStart', [this]);
}

RomoTooltip.prototype.doLoadBodySuccess = function(data) {
  Romo.initUpdateHtml(this.bodyElem, data);
  this.doInitBody();
  this.doPlacePopupElem();
  Romo.trigger(this.elem, 'romoTooltip:loadBodySuccess', [data, this]);
}

RomoTooltip.prototype.doLoadBodyError = function(xhr) {
  Romo.trigger(this.elem, 'romoTooltip:loadBodyError', [xhr, this]);
}

RomoTooltip.prototype.onToggleEnter = function(e) {
  if (e !== undefined) {
    e.preventDefault();
  }

  this.hoverState = 'in';
  if (Romo.hasClass(this.elem, 'disabled') === false) {
    clearTimeout(this.timeout);
    this.timeout = setTimeout(Romo.proxy(function() {
      if (this.hoverState ==='in') {
        this.doPopupOpen();
      }
    }, this), this.delayEnter);
  }
}

RomoTooltip.prototype.onToggleLeave = function(e) {
  if (e !== undefined) {
    e.preventDefault();
  }

  this.hoverState = 'out';
  if (Romo.hasClass(this.elem, 'disabled') === false) {
    clearTimeout(this.timeout);
    this.timeout = setTimeout(Romo.proxy(function() {
      if (this.hoverState === 'out') {
        this.doPopupClose();
      }
    }, this), this.delayLeave);
  }
}

RomoTooltip.prototype.onResizeWindow = function(e) {
  if (Romo.hasClass(this.elem, 'disabled') === false && this.hoverState === 'in') {
    this.doPlacePopupElem();
  }
}

RomoTooltip.prototype.onPopupOpen = function(e) {
  if (e !== undefined) {
    e.preventDefault();
  }

  if (Romo.hasClass(this.elem, 'disabled') === false) {
    this.doPopupOpen();
  }
}

RomoTooltip.prototype.doPopupOpen = function() {
  if (this.romoAjax !== undefined) {
    this.romoAjax.doInvoke();
  } else {
    this._setBodyHtml(Romo.data(this.elem, 'romo-tooltip-content'));
  }
  Romo.addClass(this.popupElem, 'romo-tooltip-open');
  this.doPlacePopupElem();

  if (Romo.parents(this.elem, '.romo-modal-popup').length !== 0) {
    var bodyElem = Romo.f('body')[0];
    Romo.on(bodyElem, 'romoModal:mousemove',  Romo.proxy(this.onModalPopupChange, this));
    Romo.on(bodyElem, 'romoModal:popupclose', Romo.proxy(this.onModalPopupChange, this));
  }
  Romo.on(window, 'resize', Romo.proxy(this.onResizeWindow, this));

  Romo.trigger(this.elem, 'romoTooltip:popupOpen', [this]);
}

RomoTooltip.prototype.onPopupClose = function(e) {
  if (e !== undefined) {
    e.preventDefault();
  }

  if (Romo.hasClass(this.elem, 'disabled') === false) {
    this.doPopupClose();
  }
}

RomoTooltip.prototype.doPopupClose = function() {
  Romo.removeClass(this.popupElem, 'romo-tooltip-open');

  if (this.elem.parents('.romo-modal-popup').size() !== 0) {
    var bodyElem = Romo.f('body')[0];
    Romo.off(bodyElem, 'romoModal:mousemove',  Romo.proxy(this.onModalPopupChange, this));
    Romo.off(bodyElem, 'romoModal:popupclose', Romo.proxy(this.onModalPopupChange, this));
  }
  Romo.off(window, 'resize', Romo.proxy(this.onResizeWindow, this));

  Romo.trigger(this.elem, 'romoTooltip:popupClose', [this]);
}

RomoTooltip.prototype.onModalPopupChange = function(e) {
  if (e !== undefined) {
    this.doPopupClose();
  }
  return true;
}

RomoTooltip.prototype.onSetContent = function(e, value) {
  if (e !== undefined) {
    e.preventDefault();
  }
  this.doSetContent(value);
}

RomoTooltip.prototype.doSetContent = function(value) {
  Romo.setData(this.elem, 'romo-tooltip-content', value);
  this._setBodyHtml(Romo.data(this.elem, 'romo-tooltip-content'));
  this.doPlacePopupElem();
}

RomoTooltip.prototype.onResizeWindow = function(e) {
  this.doPlacePopupElem();
  return true;
}

RomoTooltip.prototype.doPlacePopupElem = function() {
  if (Romo.parents(this.elem, '.romo-modal-popup').length !== 0) {
    Romo.setStyle(this.popupElem, 'position', 'fixed');
  }

  var pos = Romo.assign({}, this.elem.getBoundingClientRect(), Romo.offset(this.elem));
  var w = this.popupElem.offsetWidth;
  var h = this.popupElem.offsetHeight;
  var pad = 6 + 1; // arrow size + spacing
  var offset = {};

  var configHeight = Romo.data(this.elem, 'romo-tooltip-height') || Romo.data(this.elem, 'romo-tooltip-max-height');
  var configPosition = this.popupPosition;

  if (configHeight === 'detect' && (configPosition === 'top' || configPosition === 'bottom')) {
    var popupHeight = parseInt(Romo.css(this.popupElem, 'height'));
    var topAvailHeight = this._getPopupMaxAvailableHeight('top');
    var bottomAvailHeight = this._getPopupMaxAvailableHeight('bottom');

    if (popupHeight < topAvailHeight && popupHeight < bottomAvailHeight) {
      // if it fits both ways, use the config position way
      configHeight = this._getPopupMaxAvailableHeight(configPosition);
      Romo.setData(this.popupElem, 'romo-tooltip-arrow-position', configPosition);
    } else if (topAvailHeight > bottomAvailHeight) {
      configPosition = 'top';
      configHeight = topAvailHeight;
      Romo.setData(this.popupElem, 'data-romo-tooltip-arrow-position', 'top');
    } else {
      configPosition = 'bottom';
      configHeight = bottomAvailHeight;
      Romo.setData(this.popupElem, 'data-romo-tooltip-arrow-position', 'bottom');
    }

    Romo.setStyle(this.bodyElem, 'max-height', configHeight.toString() + 'px');
  } else {
    Romo.setData(this.popupElem, 'romo-tooltip-arrow-position', configPosition);
  }

  if(h > configHeight) {
    h = configHeight;
  }

  switch (configPosition) {
    case 'top':
      Romo.assign(offset, { top: pos.top - h - pad, left: pos.left + pos.width / 2 - w / 2 });
      break;
    case 'bottom':
      Romo.assign(offset, { top: pos.top + pos.height + pad, left: pos.left + pos.width / 2 - w / 2 });
      break;
    case 'left':
      Romo.assign(offset, { top: pos.top + pos.height / 2 - h / 2, left: pos.left - w - pad });
      break;
    case 'right':
      Romo.assign(offset, { top: pos.top + pos.height / 2 - h / 2, left: pos.left + pos.width + pad });
      break;
  }

  Romo.setStyle(this.popupElem, 'top',  offset.top);
  Romo.setStyle(this.popupElem, 'left', offset.left);
}

RomoTooltip.prototype.doSetPopupZIndex = function(relativeElem) {
  var relativeZIndex = Romo.parseZIndex(relativeElem);
  Romo.setStyle(this.popupElem, 'z-index', relativeZIndex + 1100); // see z-index.css
}

// private

RomoTooltip.prototype._getPopupMaxAvailableHeight = function(position) {
  var maxHeight = undefined;

  switch (position) {
    case 'top':
      var elemTop = this.elem.getBoundingClientRect().top;
      maxHeight = elemTop - this._getPopupMaxHeightDetectPad(position);
      break;
    case 'bottom':
      var elemBottom = this.elem.getBoundingClientRect().bottom;
      maxHeight = window.innerHeight - elemBottom - this._getPopupMaxHeightDetectPad(position);
      break;
  }

  return maxHeight;
}

RomoTooltip.prototype._getPopupMaxHeightDetectPad = function(position) {
  return Romo.data(this.elem, 'romo-tooltip-max-height-detect-pad-'+position) || Romo.data(this.elem, 'romo-tooltip-max-height-detect-pad') || 10;
}

RomoTooltip.prototype._setBodyHtml = function(content) {
  Romo.updateHtml(this.bodyElem, content || '');
}

Romo.onInitUI(function(elem) {
  Romo.initUIElems(elem, '[data-romo-tooltip-auto="true"]').forEach(function(elem) { new RomoTooltip(elem); });
});
<commit_msg>romoTooltip: cleanups to get up to modern conventions<commit_after>var RomoTooltip = function(elem) {
  this.elem = elem;

  this.doInit();
  this._bindElem();

  Romo.trigger(this.elem, 'romoTooltip:ready', [this]);
}

RomoDropdown.prototype.popupOpen = function() {
  return Romo.hasClass(this.popupElem, 'romo-tooltip-open') === true;
}

RomoDropdown.prototype.popupClosed = function() {
  return Romo.hasClass(this.popupElem, 'romo-tooltip-open') === false;
}

RomoTooltip.prototype.doInit = function() {
  // override as needed
}

RomoTooltip.prototype.doPopupOpen = function() {
  if (this.romoAjax !== undefined) {
    this.romoAjax.doInvoke();
  } else {
    this._setBodyHtml(Romo.data(this.elem, 'romo-tooltip-content'));
  }
  Romo.addClass(this.popupElem, 'romo-tooltip-open');
  this.doPlacePopupElem();

  if (Romo.parents(this.elem, '.romo-modal-popup').length !== 0) {
    var bodyElem = Romo.f('body')[0];
    Romo.on(bodyElem, 'romoModal:mousemove',  Romo.proxy(this._onModalPopupChange, this));
    Romo.on(bodyElem, 'romoModal:popupclose', Romo.proxy(this._onModalPopupChange, this));
  }
  Romo.on(window, 'resize', Romo.proxy(this._onResizeWindow, this));

  Romo.trigger(this.elem, 'romoTooltip:popupOpen', [this]);
}

RomoTooltip.prototype.doPopupClose = function() {
  Romo.removeClass(this.popupElem, 'romo-tooltip-open');

  if (Romo.parents(this.elem, '.romo-modal-popup').length !== 0) {
    var bodyElem = Romo.f('body')[0];
    Romo.off(bodyElem, 'romoModal:mousemove',  Romo.proxy(this._onModalPopupChange, this));
    Romo.off(bodyElem, 'romoModal:popupclose', Romo.proxy(this._onModalPopupChange, this));
  }
  Romo.off(window, 'resize', Romo.proxy(this._onResizeWindow, this));

  Romo.trigger(this.elem, 'romoTooltip:popupClose', [this]);
}

RomoTooltip.prototype.doPlacePopupElem = function() {
  if (Romo.parents(this.elem, '.romo-modal-popup').length !== 0) {
    Romo.setStyle(this.popupElem, 'position', 'fixed');
  }

  var pos    = Romo.assign({}, this.elem.getBoundingClientRect(), Romo.offset(this.elem));
  var w      = this.popupElem.offsetWidth;
  var h      = this.popupElem.offsetHeight;
  var pad    = 6 + 1; // arrow size + spacing
  var offset = {};

  var configHeight = Romo.data(this.elem, 'romo-tooltip-height') || Romo.data(this.elem, 'romo-tooltip-max-height');
  var configPosition = this.popupPosition;

  if (configHeight === 'detect' && (configPosition === 'top' || configPosition === 'bottom')) {
    var popupHeight = parseInt(Romo.css(this.popupElem, 'height'));
    var topAvailHeight = this._getPopupMaxAvailableHeight('top');
    var bottomAvailHeight = this._getPopupMaxAvailableHeight('bottom');

    if (popupHeight < topAvailHeight && popupHeight < bottomAvailHeight) {
      // if it fits both ways, use the config position way
      configHeight = this._getPopupMaxAvailableHeight(configPosition);
      Romo.setData(this.popupElem, 'romo-tooltip-arrow-position', configPosition);
    } else if (topAvailHeight > bottomAvailHeight) {
      configPosition = 'top';
      configHeight   = topAvailHeight;
      Romo.setData(this.popupElem, 'data-romo-tooltip-arrow-position', 'top');
    } else {
      configPosition = 'bottom';
      configHeight   = bottomAvailHeight;
      Romo.setData(this.popupElem, 'data-romo-tooltip-arrow-position', 'bottom');
    }

    Romo.setStyle(this.bodyElem, 'max-height', configHeight.toString() + 'px');
  } else {
    Romo.setData(this.popupElem, 'romo-tooltip-arrow-position', configPosition);
  }

  if(h > configHeight) {
    h = configHeight;
  }

  switch (configPosition) {
    case 'top':
      Romo.assign(offset, { top: pos.top - h - pad, left: pos.left + pos.width / 2 - w / 2 });
      break;
    case 'bottom':
      Romo.assign(offset, { top: pos.top + pos.height + pad, left: pos.left + pos.width / 2 - w / 2 });
      break;
    case 'left':
      Romo.assign(offset, { top: pos.top + pos.height / 2 - h / 2, left: pos.left - w - pad });
      break;
    case 'right':
      Romo.assign(offset, { top: pos.top + pos.height / 2 - h / 2, left: pos.left + pos.width + pad });
      break;
  }

  Romo.setStyle(this.popupElem, 'top',  offset.top);
  Romo.setStyle(this.popupElem, 'left', offset.left);
}

RomoTooltip.prototype.doSetContent = function(value) {
  Romo.setData(this.elem, 'romo-tooltip-content', value);
  this._setBodyHtml(Romo.data(this.elem, 'romo-tooltip-content'));
  this.doPlacePopupElem();
}

// private

RomoDropdown.prototype._bindElem = function() {
  this._bindPopup();
  if (Romo.data(this.elem, 'romo-tooltip-content') === undefined) {
    this._bindAjax();
  }
  this._bindBody();

  this.hoverState = 'out';
  this.delayEnter = 0;
  this.delayLeave = 0;

  if (Romo.data(this.elem, 'romo-tooltip-delay') !== undefined && Romo.data(this.elem, 'romo-tooltip-delay') !== '') {
    this.delayEnter = Romo.data(this.elem, 'romo-tooltip-delay');
    this.delayLeave = Romo.data(this.elem, 'romo-tooltip-delay');
  }
  if (Romo.data(this.elem, 'romo-tooltip-delay-enter') !== undefined && Romo.data(this.elem, 'romo-tooltip-delay-enter') !== '') {
    this.delayEnter = Romo.data(this.elem, 'romo-tooltip-delay-enter');
  }
  if (Romo.data(this.elem, 'romo-tooltip-delay-leave') !== undefined && Romo.data(this.elem, 'romo-tooltip-delay-leave') !== '') {
    this.delayLeave = Romo.data(this.elem, 'romo-tooltip-delay-leave');
  }

  Romo.on(this.elem, 'mouseenter',                    Romo.proxy(this._onToggleEnter, this));
  Romo.on(this.elem, 'mouseleave',                    Romo.proxy(this._onToggleLeave, this));
  Romo.on(this.elem, 'romoTooltip:triggerPopupOpen',  Romo.proxy(this._onPopupOpen,   this));
  Romo.on(this.elem, 'romoTooltip:triggerPopupClose', Romo.proxy(this._onPopupClose,  this));
  Romo.on(this.elem, 'romoTooltip:triggerSetContent', Romo.proxy(this._onSetContent,  this));

  Romo.on(window, 'resize', Romo.proxy(this._onResizeWindow, this))
}

RomoDropdown.prototype._bindPopup = function() {
  this.popupElem = Romo.elems('

')[0];
  var popupParentElem = Romo.closest(this.elem, Romo.data(this.elem, 'romo-tooltip-append-to-closest') || 'body');
  Romo.append(popupParentElem, this.popupElem);

  this.bodyElem = Romo.find(this.popupElem, '> .romo-tooltip-body')[0];
  if (Romo.data(this.elem, 'romo-tooltip-style-class') !== undefined) {
    Romo.addClass(this.bodyElem, Romo.data(this.elem, 'romo-tooltip-style-class'));
  }

  this.popupPosition = Romo.data(this.elem, 'romo-tooltip-position') || 'top';
  Romo.setData(this.popupElem, 'romo-tooltip-position', this.popupPosition);

  this.popupAlignment = Romo.data(this.elem, 'romo-tooltip-alignment') || 'center';
  Romo.setData(this.popupElem, 'romo-tooltip-alignment', this.popupAlignment);

  this._setPopupZIndex(this.elem);

  // don't propagate click events on the popup elem.  this prevents the popup
  // from closing when clicked (see body click event bind on popup open)
  Romo.on(this.popupElem, 'click', function(e) {
    e.stopPropagation();
  })

  // the popup should be treated like a child elem.  add it to Romo's
  // parent-child elems so it will be removed when the elem is removed.
  // delay adding it b/c other components may `append` generated tooltips
  // meaning the tooltip is removed and then re-added.  if added immediately
  // the "remove" part will incorrectly remove the popup.
  setTimeout(Romo.proxy(function() {
    Romo.parentChildElems.add(this.elem, [this.popupElem]);
  }, this), 1);
}

RomoTooltip.prototype._bindAjax = function() {
  this.romoAjax = new RomoAjax(this.elem);
  this.romoAjax.doUnbindElem(); // disable auto invoke on click

  Romo.on(this.elem, 'romoAjax:callStart', Romo.proxy(function(e, romoAjax) {
    this._loadBodyStart();
    return false;
  }, this));
  Romo.on(this.elem, 'romoAjax:callSuccess', Romo.proxy(function(e, data, romoAjax) {
    this._loadBodySuccess(data);
    return false;
  }, this));
  Romo.on(this.elem, 'romoAjax:callError', Romo.proxy(function(e, xhr, romoAjax) {
    this._loadBodyError(xhr);
    return false;
  }, this));
}

RomoTooltip.prototype._bindBody = function() {
  this._resetBody();

  Romo.setStyle(this.bodyElem, 'min-width',  Romo.data(this.elem, 'romo-tooltip-min-width'));
  Romo.setStyle(this.bodyElem, 'max-width',  Romo.data(this.elem, 'romo-tooltip-max-width'));
  Romo.setStyle(this.bodyElem, 'width',      Romo.data(this.elem, 'romo-tooltip-width'));
  Romo.setStyle(this.bodyElem, 'min-height', Romo.data(this.elem, 'romo-tooltip-min-height'));
  Romo.setStyle(this.bodyElem, 'height',     Romo.data(this.elem, 'romo-tooltip-height'));

  if (Romo.data(this.elem, 'romo-tooltip-max-height') === undefined) {
    Romo.setData(this.elem, 'romo-tooltip-max-height', 'detect');
  }
  if (Romo.data(this.elem, 'romo-tooltip-max-height') !== 'detect') {
    Romo.setStyle(this.bodyElem, 'max-height', Romo.data(this.elem, 'romo-tooltip-max-height'));
  }
}

RomoTooltip.prototype._resetBody = function() {
  Romo.setStyle(this.bodyElem, 'min-width',  '');
  Romo.setStyle(this.bodyElem, 'max-width',  '');
  Romo.setStyle(this.bodyElem, 'width',      '');
  Romo.setStyle(this.bodyElem, 'min-height', '');
  Romo.setStyle(this.bodyElem, 'max-height', '');
  Romo.setStyle(this.bodyElem, 'height',     '');
}

RomoTooltip.prototype._loadBodyStart = function() {
  this._setBodyHtml('');
  this._bindBody();
  this.doPlacePopupElem();
  Romo.trigger(this.elem, 'romoTooltip:loadBodyStart', [this]);
}

RomoTooltip.prototype._loadBodySuccess = function(data) {
  Romo.initUpdateHtml(this.bodyElem, data);
  this._bindBody();
  this.doPlacePopupElem();
  Romo.trigger(this.elem, 'romoTooltip:loadBodySuccess', [data, this]);
}

RomoTooltip.prototype._loadBodyError = function(xhr) {
  Romo.trigger(this.elem, 'romoTooltip:loadBodyError', [xhr, this]);
}

RomoTooltip.prototype._onToggleEnter = function(e) {
  this.hoverState = 'in';
  if (Romo.hasClass(this.elem, 'disabled') === false) {
    clearTimeout(this.timeout);
    this.timeout = setTimeout(Romo.proxy(function() {
      if (this.hoverState ==='in') {
        this.doPopupOpen();
      }
    }, this), this.delayEnter);
  }

  return false;
}

RomoTooltip.prototype._onToggleLeave = function(e) {
  this.hoverState = 'out';
  if (Romo.hasClass(this.elem, 'disabled') === false) {
    clearTimeout(this.timeout);
    this.timeout = setTimeout(Romo.proxy(function() {
      if (this.hoverState === 'out') {
        this.doPopupClose();
      }
    }, this), this.delayLeave);
  }

  return false;
}

RomoTooltip.prototype._onPopupOpen = function(e) {
  if (Romo.hasClass(this.elem, 'disabled') === false) {
    this.doPopupOpen();
  }
}

RomoTooltip.prototype._onPopupClose = function(e) {
  this.doPopupClose();
}

RomoTooltip.prototype._onModalPopupChange = function(e) {
  this.doPopupClose();
}

RomoTooltip.prototype._onSetContent = function(e, value) {
  this.doSetContent(value);
}

RomoTooltip.prototype._onResizeWindow = function(e) {
  this.doPlacePopupElem();
}

RomoTooltip.prototype._setPopupZIndex = function(relativeElem) {
  var relativeZIndex = Romo.parseZIndex(relativeElem);
  Romo.setStyle(this.popupElem, 'z-index', relativeZIndex + 1100); // see z-index.css
}

RomoTooltip.prototype._getPopupMaxAvailableHeight = function(position) {
  var maxHeight = undefined;

  switch (position) {
    case 'top':
      var elemTop = this.elem.getBoundingClientRect().top;
      maxHeight = elemTop - this._getPopupMaxHeightDetectPad(position);
      break;
    case 'bottom':
      var elemBottom = this.elem.getBoundingClientRect().bottom;
      maxHeight = window.innerHeight - elemBottom - this._getPopupMaxHeightDetectPad(position);
      break;
  }

  return maxHeight;
}

RomoTooltip.prototype._getPopupMaxHeightDetectPad = function(position) {
  return (
    Romo.data(this.elem, 'romo-tooltip-max-height-detect-pad-'+position) ||
    Romo.data(this.elem, 'romo-tooltip-max-height-detect-pad')           ||
    10
  );
}

RomoTooltip.prototype._setBodyHtml = function(content) {
  Romo.updateHtml(this.bodyElem, content || '');
}

Romo.onInitUI(function(elem) {
  Romo.initUIElems(elem, '[data-romo-tooltip-auto="true"]').forEach(function(elem) { new RomoTooltip(elem); });
});
<|endoftext|>


<commit_before>'use strict';

var d = require('d/d')

  , defineProperties = Object.defineProperties
  , generateName, Symbol;

generateName = (function () {
	var created = Object.create(null);
	return function (desc) {
		var postfix = 0;
		while (created[desc + (postfix || '')]) ++postfix;
		desc += (postfix || '');
		created[desc] = true;
		return '@@' + desc;
	};
}());

module.exports = Symbol = function (description) {
	if (!(this instanceof Symbol)) return new Symbol(description);
	description = (description === undefined ? '' : String(description));
	return defineProperties(this, {
		__description__: d('', description),
		__name__: d('', generateName(description))
	});
};

Object.defineProperties(Symbol, {
	create: d('', new Symbol('create')),
	hasInstance: d('', new Symbol('hasInstance')),
	isConcatSpreadable: d('', new Symbol('isConcatSpreadable')),
	isRegExp: d('', new Symbol('isRegExp')),
	iterator: d('', new Symbol('iterator')),
	toPrimitive: d('', new Symbol('toPrimitive')),
	toStringTag: d('', new Symbol('toStringTag')),
	unscopables: d('', new Symbol('unscopables'))
});

defineProperties(Symbol.prototype, {
	properToString: d(function () {
		return 'Symbol (' + this.__description__ + ')';
	}),
	toString: d('', function () { return this.__name__; })
});
Object.defineProperty(Symbol.prototype, 'originalToString', d(function () {
	return 'Symbol (' + this.__description__ + ')';
}));
Object.defineProperty(Symbol.prototype, Symbol.toPrimitive, d('',
	function (hint) {
		throw new TypeError("Conversion of symbol objects is not allowed");
	}));
Object.defineProperty(Symbol.prototype, Symbol.toStringTag, d('c', 'Symbol'));
<commit_msg>Remove duplicated code<commit_after>'use strict';

var d = require('d/d')

  , defineProperties = Object.defineProperties
  , generateName, Symbol;

generateName = (function () {
	var created = Object.create(null);
	return function (desc) {
		var postfix = 0;
		while (created[desc + (postfix || '')]) ++postfix;
		desc += (postfix || '');
		created[desc] = true;
		return '@@' + desc;
	};
}());

module.exports = Symbol = function (description) {
	if (!(this instanceof Symbol)) return new Symbol(description);
	description = (description === undefined ? '' : String(description));
	return defineProperties(this, {
		__description__: d('', description),
		__name__: d('', generateName(description))
	});
};

Object.defineProperties(Symbol, {
	create: d('', new Symbol('create')),
	hasInstance: d('', new Symbol('hasInstance')),
	isConcatSpreadable: d('', new Symbol('isConcatSpreadable')),
	isRegExp: d('', new Symbol('isRegExp')),
	iterator: d('', new Symbol('iterator')),
	toPrimitive: d('', new Symbol('toPrimitive')),
	toStringTag: d('', new Symbol('toStringTag')),
	unscopables: d('', new Symbol('unscopables'))
});

defineProperties(Symbol.prototype, {
	properToString: d(function () {
		return 'Symbol (' + this.__description__ + ')';
	}),
	toString: d('', function () { return this.__name__; })
});
Object.defineProperty(Symbol.prototype, Symbol.toPrimitive, d('',
	function (hint) {
		throw new TypeError("Conversion of symbol objects is not allowed");
	}));
Object.defineProperty(Symbol.prototype, Symbol.toStringTag, d('c', 'Symbol'));
<|endoftext|>


<commit_before>(function() {
  var Resolver = require('resolver').default;

  function resolveRouter(parsedName) {
    /*jshint validthis:true */

    var prefix = this.namespace.configPrefix,
        routerModule;

    if (parsedName.fullName === 'router:main') {
      // for now, lets keep the router at app/router.js
      if (requirejs._eak_seen[prefix + '/router']) {
        routerModule = require(prefix + '/router');
        if (routerModule['default']) { routerModule = routerModule['default']; }

        return routerModule;
      }
    }
  }

  function resolveAdapter(parsedName) {
    /*jshint validthis:true */

    var prefix = this.namespace.configPrefix,
        adapterModule, adapterName;

    if (parsedName.fullName.match(/adapter:/)) {
      adapterName = parsedName.fullName.split(/adapter:/)[1];
      if (requirejs._eak_seen[prefix + '/adapters/' + adapterName]) {
        adapterModule = require(prefix + '/adapters/' + adapterName);
        if (adapterModule['default']) { adapterModule = adapterModule['default']; }

        return adapterModule;
      }
    }
  }

  Resolver.reopen({
    resolveRouter: resolveRouter,
    resolveAdapter: resolveAdapter
  });
})();
<commit_msg>Adds serializer resolver<commit_after>(function() {
  var Resolver = require('resolver').default;

  function resolveRouter(parsedName) {
    /*jshint validthis:true */

    var prefix = this.namespace.configPrefix,
        routerModule;

    if (parsedName.fullName === 'router:main') {
      // for now, lets keep the router at app/router.js
      if (requirejs._eak_seen[prefix + '/router']) {
        routerModule = require(prefix + '/router');
        if (routerModule['default']) { routerModule = routerModule['default']; }

        return routerModule;
      }
    }
  }

  function resolveSerializer(parsedName) {
    /*jshint validthis:true */

    var prefix = this.namespace.configPrefix,
        serializerModule, serializerName;

    if (parsedName.fullName.match(/serializer:/)) {
      serializerName = parsedName.fullName.split(/serializer:/)[1];
      if (requirejs._eak_seen[prefix + '/serializers/' + serializerName]) {
        serializerModule = require(prefix + '/serializers/' + serializerName);
        if (serializerModule['default']) { serializerModule = serializerModule['default']; }

        return serializerModule;
      }
    }
  }

  function resolveAdapter(parsedName) {
    /*jshint validthis:true */

    var prefix = this.namespace.configPrefix,
        adapterModule, adapterName;

    if (parsedName.fullName.match(/adapter:/)) {
      adapterName = parsedName.fullName.split(/adapter:/)[1];
      if (requirejs._eak_seen[prefix + '/adapters/' + adapterName]) {
        adapterModule = require(prefix + '/adapters/' + adapterName);
        if (adapterModule['default']) { adapterModule = adapterModule['default']; }

        return adapterModule;
      }
    }
  }

  Resolver.reopen({
    resolveRouter: resolveRouter,
    resolveAdapter: resolveAdapter
  });
})();
<|endoftext|>


<commit_before>/*
 * Copyright (c) WSO2 Inc. (http://wso2.com) All Rights Reserved.
 *
 *   Licensed 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
 *
 *        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.
 */
asset.manager = function(ctx) {
    var notifier = require('store').notificationManager;
    var storeConstants = require('store').storeConstants;
    var COMMENT = 'User comment';
    var carbon = require('carbon');
    var social = carbon.server.osgiService('org.wso2.carbon.social.core.service.SocialActivityService');
    var log = new Log('default-asset');
    return {
        create: function(options) {
            var ref = require('utils').time;
            //Check if the options object has a createdtime attribute and populate it
            if ((options.attributes) && ctx.rxtManager.getRxtField(ctx.assetType, 'overview_createdtime')) {
                options.attributes.overview_createdtime = ref.getCurrentTime();
            }
            this._super.create.call(this, options);
            var asset = this.get(options.id); //TODO avoid get: expensive operation
            var assetPath = asset.path;
            var user = ctx.username;
            var userRoles = ctx.userManager.getRoleListOfUser(user);
            try {
                social.warmUpRatingCache(ctx.assetType + ':' + options.id);
            } catch (e) {
                log.warn("Unable to publish the asset: " + ctx.assetType + ":" + options.id + " to social cache. This may affect on sort by popularity function.");
            }
            //Check whether the user has admin role
            var endpoint = storeConstants.PRIVATE_ROLE_ENDPOINT + user;
            for (var role in userRoles) {
                if (userRoles.hasOwnProperty(role) && userRoles[role] == storeConstants.ADMIN_ROLE) {
                    endpoint = storeConstants.ADMIN_ROLE_ENDPOINT;
                }
            }

            var provider = ctx.username;

            if(options.attributes.overview_provider){
                provider = options.attributes.overview_provider;
            }
            provider = provider.replace(':', '@');
            //Subscribe the asset author for LC update event and asset update event
            notifier.subscribeToEvent(provider, assetPath, endpoint, storeConstants.LC_STATE_CHANGE);
            notifier.subscribeToEvent(provider, assetPath, endpoint, storeConstants.ASSET_UPDATE);
        },
        update: function(options) {
            this._super.update.call(this, options);
            var asset = this.get(options.id); //TODO avoid get: expensive operation
            //trigger notification on asset update
            notifier.notifyEvent(storeConstants.ASSET_UPDATE_EVENT, asset.type, asset.name, null, asset.path, ctx.tenantId);
        },
        search: function(query, paging) {
            return this._super.search.call(this, query, paging);
        },
        list: function(paging) {
            return this._super.list.call(this, paging);
        },
        get: function(id) {
            return this._super.get.call(this, id);
        },
        invokeLcAction: function(asset, action, lcName) {
            var success;
            if (lcName) {
                success = this._super.invokeLcAction.call(this, asset, action, lcName);
            } else {
                success = this._super.invokeLcAction.call(this, asset, action);
            }
            //trigger notification on LC state change
            notifier.notifyEvent(storeConstants.LC_STATE_CHANGE_EVENT, asset.type, asset.name, COMMENT, asset.path, ctx.tenantId);
            return success;
        }
    };
};
asset.server = function(ctx) {
    var type = ctx.type;
    return {
        onUserLoggedIn: function() {},
        endpoints: {
            apis: [{
                url: 'assets',
                path: 'assets.jag'
            }, {
                url: 'asset',
                path: 'asset.jag'
            }, {
                url: 'statistics',
                path: 'statistics.jag'
            }],
            pages: [{
                title: 'Asset: ' + type,
                url: 'asset',
                path: 'asset.jag'
            }, {
                title: 'Assets ' + type,
                url: 'assets',
                path: 'assets.jag'
            }, {
                title: 'Create ' + type,
                url: 'create',
                path: 'create.jag',
                permission: 'ASSET_CREATE'
            }, {
                title: 'Update ' + type,
                url: 'update',
                path: 'update.jag',
                permission: 'ASSET_UPDATE'
            }, {
                title: 'Details ' + type,
                url: 'details',
                path: 'details.jag'
            }, {
                title: 'List ' + type,
                url: 'list',
                path: 'list.jag',
                permission: 'ASSET_LIST'
            }, {
                title: 'Lifecycle',
                url: 'lifecycle',
                path: 'lifecycle.jag',
                permission: 'ASSET_LIFECYCLE'
            }, {
                title: 'Old lifecycle ',
                url: 'old-lifecycle',
                path: 'old-lifecycle.jag'
            }, {
                title: 'Statistics',
                url: 'statistics',
                path: 'statistics.jag'
            }, {
                title: 'Copy ' + type,
                url: 'copy',
                path: 'copy.jag',
                permission: 'ASSET_CREATE'
            }, {
                title: 'Delete ' + type,
                url: 'delete',
                path: 'delete.jag'
            }]
        }
    };
};
asset.configure = function() {
    return {
        table: {
            overview: {
                fields: {
                    provider: {
                        auto: true
                    },
                    name: {
                        name: {
                            name: 'name',
                            label: 'Name'
                        },
                        readonly: true,
                        required:true,
                        validation: function() {}
                    },
                    version: {
                        name: {
                            label: 'Version'
                        },
                        readonly: true,
                        required:true
                    },
                    createdtime: {
                        hidden: true
                    }
                }
            },
            images: {
                fields: {
                    thumbnail: {
                        type: 'file'
                    },
                    banner: {
                        type: 'file'
                    }
                }
            }
        },
        meta: {
            lifecycle: {
                name: 'SampleLifeCycle2',
                commentRequired: false,
                defaultLifecycleEnabled: true,
                defaultAction: 'Promote',
                deletableStates: ['Unpublished'],
                publishedStates: ['Published'],
                lifecycleEnabled: true
            },
            ui: {
                icon: 'fw fw-resource'
            },
            categories: {
                categoryField: 'overview_category'
            },
            thumbnail: 'images_thumbnail',
            banner: 'images_banner',
            nameAttribute: 'overview_name',
            versionAttribute: 'overview_version',
            providerAttribute: 'overview_provider',
            timestamp: 'overview_createdtime',
            grouping: {
                groupingEnabled: false,
                groupingAttributes: ['overview_name']
            },
            permissions: {
                configureRegistryPermissions: function(ctx) {
                }
            }
        }
    };
};
asset.renderer = function(ctx) {
    var type = ctx.assetType;
    var permissionAPI = require('rxt').permissions;
    var isAssetWithLifecycle = function(asset) {
        if ((asset.lifecycle) && (asset.lifecycleState)) {
            return true;
        }
        if (log.isDebugEnabled()) {
            log.debug('asset: ' + asset.name + ' does not have a lifecycle or a state.The lifecycle view will not be rendered for this asset');
        }
        return false;
    };
    var buildListLeftNav = function(page, util) {
        var navList = util.navList();
        if (permissionAPI.hasAssetPermission(permissionAPI.ASSET_CREATE, ctx.assetType, ctx.session)) {
            navList.push('Add ' + type, 'btn-add-new', util.buildUrl('create'));
            navList.push('Statistics', 'btn-stats', '/assets/' + type + '/statistics');
        }
        //navList.push('Configuration', 'icon-dashboard', util.buildUrl('configuration'));
        return navList.list();
    };
    var buildDefaultLeftNav = function(page, util) {
        var id = page.assets.id;
        var path = page.assets.path;
        var navList = util.navList();
        var isLCViewEnabled = ctx.rxtManager.isLifecycleViewEnabled(ctx.assetType);
        var user = require('store').server.current(session);
        var username = user? user.username : null;
        if (permissionAPI.hasActionPermissionforPath(path, 'write', ctx.session) && permissionAPI.hasAssetPagePermission(type,'update',user.tenantId,username)) {
            navList.push('Edit', 'btn-edit', util.buildUrl('update') + '/' + id);
            navList.push('Version', 'btn-copy', util.buildUrl('copy') + '/' + id);
        }
        navList.push('Overview', 'btn-overview', util.buildUrl('details') + '/' + id);
        //Only render the view if the asset has a
        if ((isLCViewEnabled) && (isAssetWithLifecycle(page.assets))) {
            if (permissionAPI.hasAssetPermission(permissionAPI.ASSET_LIFECYCLE, ctx.assetType, ctx.session)) {
                navList.push('Life Cycle', 'btn-lifecycle', util.buildUrl('lifecycle') + '/' + id);
            }
        }
        if (permissionAPI.hasActionPermissionforPath(path, 'delete', ctx.session)) {
            navList.push('Delete', 'btn-delete', util.buildUrl('delete') + '/' + id);
        }
        return navList.list();
    };
    var buildAddLeftNav = function(page, util) {
        return [];
    };
    var isActivatedAsset = function(assetType) {
        var app = require('rxt').app;
        var activatedAssets = app.getUIActivatedAssets(ctx.tenantId); //ctx.tenantConfigs.assets;
        //return true;
        if (!activatedAssets) {
            throw 'Unable to load all activated assets for current tenant: ' + ctx.tenatId + '.Make sure that the assets property is present in the tenant config';
        }
        for (var index in activatedAssets) {
            if (activatedAssets[index] == assetType) {
                return true;
            }
        }
        return false;
    };
    return {
        list: function(page) {
            var assets = page.assets;
            for (var index in assets) {
                var asset = assets[index];
                var timestampAttribute = ctx.rxtManager.getTimeStampAttribute(ctx.assetType);
                if (asset.attributes.hasOwnProperty(timestampAttribute)) {
                    var value = asset.attributes[timestampAttribute];
                    var date = new Date();
                    date.setTime(value);
                    asset.attributes[timestampAttribute] = date.toUTCString();
                }
            }
            require('/modules/page-decorators.js').pageDecorators.assetCategoryDetails(ctx, page, this);
        },
        details: function(page) {
            var tables = page.assets.tables;
            //TODO:This cannot be hardcoded
            var timestampAttribute = 'createdtime'; //ctx.rxtManager.getTimeStampAttribute(this.assetType);
            for (var index in tables) {
                var table = tables[index];
                if ((table.name == 'overview') && (table.fields.hasOwnProperty(timestampAttribute))) {
                    var value = table.fields[timestampAttribute].value || '';
                    var date = new Date();
                    date.setTime(value);
                    table.fields[timestampAttribute].value = date.toUTCString();
                }
            }
        },
        create: function(page) {
            var tables = page.assets.tables;
            var providerAttribute = 'provider';
            for (var index in tables) {
                var table = tables[index];
                if ((table.name == 'overview') && (table.fields.hasOwnProperty(providerAttribute))) {
                    table.fields[providerAttribute].value = page.cuser.username;
                }
            }
        },
        update: function(page) {
            var tables = page.assets.tables;
            var timestampAttribute = 'createdtime';
            for (var index in tables) {
                var table = tables[index];
                if ((table.name == 'overview') && (table.fields.hasOwnProperty(timestampAttribute))) {
                    var value = table.fields[timestampAttribute].value;
                    var date = new Date();
                    date.setTime(value);
                    table.fields[timestampAttribute].value = date.toUTCString();
                }
            }
        },
        pageDecorators: {
            leftNav: function(page) {
                if (log.isDebugEnabled()) {
                    log.debug('Using default leftNav');
                }
                switch (page.meta.pageName) {
                    case 'list':
                        page.leftNav = buildListLeftNav(page, this);
                        break;
                    case 'create':
                        page.leftNav = buildAddLeftNav(page, this);
                        break;
                    case 'statistics':
                        page.leftNav = buildListLeftNav(page, this);
                        break;
                    default:
                        page.leftNav = buildDefaultLeftNav(page, this);
                        break;
                }
                if (page.leftNav) {
                    for (var navItem in page.leftNav) {
                        if (page.leftNav[navItem].name) {
                            page.leftNav[navItem].id = page.leftNav[navItem].name.replace(/\s/g, "");
                        }
                    }
                }
                return page;
            },
            ribbon: function(page) {
                var ribbon = page.ribbon = {};
                var DEFAULT_ICON = 'fw fw-circle';
                var assetTypes = [];
                var assetType;
                var assetList = ctx.rxtManager.listRxtTypeDetails();
                for (var index in assetList) {
                    assetType = assetList[index];
                    //Only populate the link if the asset type is activated and the logged in user has permission to that asset
                    if ((isActivatedAsset(assetType.shortName)) && (permissionAPI.hasAssetPermission(permissionAPI.ASSET_LIST, assetType.shortName, ctx.session))) {
                        assetTypes.push({
                            url: this.buildBaseUrl(assetType.shortName) + '/list',
                            assetIcon: assetType.ui.icon || DEFAULT_ICON,
                            assetTitle: assetType.singularLabel
                        });
                    }
                }
                ribbon.currentType = page.rxt.singularLabel;
                ribbon.currentTitle = page.rxt.singularLabel;
                ribbon.currentUrl = this.buildBaseUrl(type) + '/list'; //page.meta.currentPage;
                ribbon.shortName = page.rxt.singularLabel;
                ribbon.query = 'Query';
                ribbon.breadcrumb = assetTypes;
                return page;
            },
            populateAttachedLifecycles: function(page) {
                if (page.assets.id) {
                    require('/modules/page-decorators.js').pageDecorators.populateAttachedLifecycles(ctx, page, this);
                }
            },
            populateAssetVersionDetails: function(page) {
                if (page.assets.id) {
                    require('/modules/page-decorators.js').pageDecorators.populateAssetVersionDetails(ctx, page, this);
                }
            },
            populateGroupingFeatureDetails: function(page) {
                require('/modules/page-decorators.js').pageDecorators.populateGroupingFeatureDetails(ctx, page);
            },
            populateTags: function(page){
                if(page.assets.id){
                    require('/modules/page-decorators.js').pageDecorators.populateTagDetails(ctx,page);
                }
            },
            sorting: function(page){
                require('/modules/page-decorators.js').pageDecorators.sorting(ctx,page);
            }
        }
    };
};
<commit_msg>Fix for STORE-1111<commit_after>/*
 * Copyright (c) WSO2 Inc. (http://wso2.com) All Rights Reserved.
 *
 *   Licensed 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
 *
 *        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.
 */
asset.manager = function(ctx) {
    var notifier = require('store').notificationManager;
    var storeConstants = require('store').storeConstants;
    var COMMENT = 'User comment';
    var carbon = require('carbon');
    var social = carbon.server.osgiService('org.wso2.carbon.social.core.service.SocialActivityService');
    var log = new Log('default-asset');
    return {
        create: function(options) {
            var ref = require('utils').time;
            //Check if the options object has a createdtime attribute and populate it
            if ((options.attributes) && ctx.rxtManager.getRxtField(ctx.assetType, 'overview_createdtime')) {
                options.attributes.overview_createdtime = ref.getCurrentTime();
            }
            this._super.create.call(this, options);
            var asset = this.get(options.id); //TODO avoid get: expensive operation
            var assetPath = asset.path;
            var user = ctx.username;
            var userRoles = ctx.userManager.getRoleListOfUser(user);
            try {
                social.warmUpRatingCache(ctx.assetType + ':' + options.id);
            } catch (e) {
                log.warn("Unable to publish the asset: " + ctx.assetType + ":" + options.id + " to social cache. This may affect on sort by popularity function.");
            }
            //Check whether the user has admin role
            var endpoint = storeConstants.PRIVATE_ROLE_ENDPOINT + user;
            for (var role in userRoles) {
                if (userRoles.hasOwnProperty(role) && userRoles[role] == storeConstants.ADMIN_ROLE) {
                    endpoint = storeConstants.ADMIN_ROLE_ENDPOINT;
                }
            }

            var provider = ctx.username;

            if(options.attributes.overview_provider){
                provider = options.attributes.overview_provider;
            }
            provider = provider.replace(':', '@');
            //Subscribe the asset author for LC update event and asset update event
            notifier.subscribeToEvent(provider, assetPath, endpoint, storeConstants.LC_STATE_CHANGE);
            notifier.subscribeToEvent(provider, assetPath, endpoint, storeConstants.ASSET_UPDATE);
        },
        update: function(options) {
            this._super.update.call(this, options);
            var asset = this.get(options.id); //TODO avoid get: expensive operation
            //trigger notification on asset update
            notifier.notifyEvent(storeConstants.ASSET_UPDATE_EVENT, asset.type, asset.name, null, asset.path, ctx.tenantId);
        },
        search: function(query, paging) {
            return this._super.search.call(this, query, paging);
        },
        list: function(paging) {
            return this._super.list.call(this, paging);
        },
        get: function(id) {
            return this._super.get.call(this, id);
        },
        invokeLcAction: function(asset, action, lcName) {
            var success;
            if (lcName) {
                success = this._super.invokeLcAction.call(this, asset, action, lcName);
            } else {
                success = this._super.invokeLcAction.call(this, asset, action);
            }
            //trigger notification on LC state change
            notifier.notifyEvent(storeConstants.LC_STATE_CHANGE_EVENT, asset.type, asset.name, COMMENT, asset.path, ctx.tenantId);
            return success;
        }
    };
};
asset.server = function(ctx) {
    var type = ctx.type;
    return {
        onUserLoggedIn: function() {},
        endpoints: {
            apis: [{
                url: 'assets',
                path: 'assets.jag'
            }, {
                url: 'asset',
                path: 'asset.jag'
            }, {
                url: 'statistics',
                path: 'statistics.jag'
            }],
            pages: [{
                title: 'Asset: ' + type,
                url: 'asset',
                path: 'asset.jag'
            }, {
                title: 'Assets ' + type,
                url: 'assets',
                path: 'assets.jag'
            }, {
                title: 'Create ' + type,
                url: 'create',
                path: 'create.jag',
                permission: 'ASSET_CREATE'
            }, {
                title: 'Update ' + type,
                url: 'update',
                path: 'update.jag',
                permission: 'ASSET_UPDATE'
            }, {
                title: 'Details ' + type,
                url: 'details',
                path: 'details.jag'
            }, {
                title: 'List ' + type,
                url: 'list',
                path: 'list.jag',
                permission: 'ASSET_LIST'
            }, {
                title: 'Lifecycle',
                url: 'lifecycle',
                path: 'lifecycle.jag',
                permission: 'ASSET_LIFECYCLE'
            }, {
                title: 'Old lifecycle ',
                url: 'old-lifecycle',
                path: 'old-lifecycle.jag'
            }, {
                title: 'Statistics',
                url: 'statistics',
                path: 'statistics.jag'
            }, {
                title: 'Copy ' + type,
                url: 'copy',
                path: 'copy.jag',
                permission: 'ASSET_CREATE'
            }, {
                title: 'Delete ' + type,
                url: 'delete',
                path: 'delete.jag'
            }]
        }
    };
};
asset.configure = function() {
    return {
        table: {
            overview: {
                fields: {
                    provider: {
                        auto: true
                    },
                    name: {
                        name: {
                            name: 'name',
                            label: 'Name'
                        },
                        readonly: true,
                        required:true,
                        validation: function() {}
                    },
                    version: {
                        name: {
                            label: 'Version'
                        },
                        readonly: true,
                        required:true
                    },
                    createdtime: {
                        hidden: true
                    }
                }
            },
            images: {
                fields: {
                    thumbnail: {
                        type: 'file'
                    },
                    banner: {
                        type: 'file'
                    }
                }
            }
        },
        meta: {
            lifecycle: {
                name: 'SampleLifeCycle2',
                commentRequired: false,
                defaultLifecycleEnabled: true,
                defaultAction: 'Promote',
                deletableStates: ['Unpublished'],
                publishedStates: ['Published'],
                lifecycleEnabled: true
            },
            ui: {
                icon: 'fw fw-resource'
            },
            categories: {
                categoryField: 'overview_category'
            },
            thumbnail: 'images_thumbnail',
            banner: 'images_banner',
            nameAttribute: 'overview_name',
            versionAttribute: 'overview_version',
            providerAttribute: 'overview_provider',
            timestamp: 'overview_createdtime',
            grouping: {
                groupingEnabled: false,
                groupingAttributes: ['overview_name']
            },
            permissions: {
                configureRegistryPermissions: function(ctx) {
                }
            }
        }
    };
};
asset.renderer = function(ctx) {
    var type = ctx.assetType;
    var permissionAPI = require('rxt').permissions;
    var isAssetWithLifecycle = function(asset) {
        if ((asset.lifecycle) && (asset.lifecycleState)) {
            return true;
        }
        if (log.isDebugEnabled()) {
            log.debug('asset: ' + asset.name + ' does not have a lifecycle or a state.The lifecycle view will not be rendered for this asset');
        }
        return false;
    };
    var buildListLeftNav = function(page, util) {
        var navList = util.navList();
        if (permissionAPI.hasAssetPermission(permissionAPI.ASSET_CREATE, ctx.assetType, ctx.session)) {
            navList.push('Add ', 'btn-add-new', util.buildUrl('create'));
            navList.push('Statistics', 'btn-stats', '/assets/' + type + '/statistics');
        }
        //navList.push('Configuration', 'icon-dashboard', util.buildUrl('configuration'));
        return navList.list();
    };
    var buildDefaultLeftNav = function(page, util) {
        var id = page.assets.id;
        var path = page.assets.path;
        var navList = util.navList();
        var isLCViewEnabled = ctx.rxtManager.isLifecycleViewEnabled(ctx.assetType);
        var user = require('store').server.current(session);
        var username = user? user.username : null;
        if (permissionAPI.hasActionPermissionforPath(path, 'write', ctx.session) && permissionAPI.hasAssetPagePermission(type,'update',user.tenantId,username)) {
            navList.push('Edit', 'btn-edit', util.buildUrl('update') + '/' + id);
            navList.push('Version', 'btn-copy', util.buildUrl('copy') + '/' + id);
        }
        navList.push('Overview', 'btn-overview', util.buildUrl('details') + '/' + id);
        //Only render the view if the asset has a
        if ((isLCViewEnabled) && (isAssetWithLifecycle(page.assets))) {
            if (permissionAPI.hasAssetPermission(permissionAPI.ASSET_LIFECYCLE, ctx.assetType, ctx.session)) {
                navList.push('Life Cycle', 'btn-lifecycle', util.buildUrl('lifecycle') + '/' + id);
            }
        }
        if (permissionAPI.hasActionPermissionforPath(path, 'delete', ctx.session)) {
            navList.push('Delete', 'btn-delete', util.buildUrl('delete') + '/' + id);
        }
        return navList.list();
    };
    var buildAddLeftNav = function(page, util) {
        return [];
    };
    var isActivatedAsset = function(assetType) {
        var app = require('rxt').app;
        var activatedAssets = app.getUIActivatedAssets(ctx.tenantId); //ctx.tenantConfigs.assets;
        //return true;
        if (!activatedAssets) {
            throw 'Unable to load all activated assets for current tenant: ' + ctx.tenatId + '.Make sure that the assets property is present in the tenant config';
        }
        for (var index in activatedAssets) {
            if (activatedAssets[index] == assetType) {
                return true;
            }
        }
        return false;
    };
    return {
        list: function(page) {
            var assets = page.assets;
            for (var index in assets) {
                var asset = assets[index];
                var timestampAttribute = ctx.rxtManager.getTimeStampAttribute(ctx.assetType);
                if (asset.attributes.hasOwnProperty(timestampAttribute)) {
                    var value = asset.attributes[timestampAttribute];
                    var date = new Date();
                    date.setTime(value);
                    asset.attributes[timestampAttribute] = date.toUTCString();
                }
            }
            require('/modules/page-decorators.js').pageDecorators.assetCategoryDetails(ctx, page, this);
        },
        details: function(page) {
            var tables = page.assets.tables;
            //TODO:This cannot be hardcoded
            var timestampAttribute = 'createdtime'; //ctx.rxtManager.getTimeStampAttribute(this.assetType);
            for (var index in tables) {
                var table = tables[index];
                if ((table.name == 'overview') && (table.fields.hasOwnProperty(timestampAttribute))) {
                    var value = table.fields[timestampAttribute].value || '';
                    var date = new Date();
                    date.setTime(value);
                    table.fields[timestampAttribute].value = date.toUTCString();
                }
            }
        },
        create: function(page) {
            var tables = page.assets.tables;
            var providerAttribute = 'provider';
            for (var index in tables) {
                var table = tables[index];
                if ((table.name == 'overview') && (table.fields.hasOwnProperty(providerAttribute))) {
                    table.fields[providerAttribute].value = page.cuser.username;
                }
            }
        },
        update: function(page) {
            var tables = page.assets.tables;
            var timestampAttribute = 'createdtime';
            for (var index in tables) {
                var table = tables[index];
                if ((table.name == 'overview') && (table.fields.hasOwnProperty(timestampAttribute))) {
                    var value = table.fields[timestampAttribute].value;
                    var date = new Date();
                    date.setTime(value);
                    table.fields[timestampAttribute].value = date.toUTCString();
                }
            }
        },
        pageDecorators: {
            leftNav: function(page) {
                if (log.isDebugEnabled()) {
                    log.debug('Using default leftNav');
                }
                switch (page.meta.pageName) {
                    case 'list':
                        page.leftNav = buildListLeftNav(page, this);
                        break;
                    case 'create':
                        page.leftNav = buildAddLeftNav(page, this);
                        break;
                    case 'statistics':
                        page.leftNav = buildListLeftNav(page, this);
                        break;
                    default:
                        page.leftNav = buildDefaultLeftNav(page, this);
                        break;
                }
                if (page.leftNav) {
                    for (var navItem in page.leftNav) {
                        if (page.leftNav[navItem].name) {
                            page.leftNav[navItem].id = page.leftNav[navItem].name.replace(/\s/g, "");
                        }
                    }
                }
                return page;
            },
            ribbon: function(page) {
                var ribbon = page.ribbon = {};
                var DEFAULT_ICON = 'fw fw-circle';
                var assetTypes = [];
                var assetType;
                var assetList = ctx.rxtManager.listRxtTypeDetails();
                for (var index in assetList) {
                    assetType = assetList[index];
                    //Only populate the link if the asset type is activated and the logged in user has permission to that asset
                    if ((isActivatedAsset(assetType.shortName)) && (permissionAPI.hasAssetPermission(permissionAPI.ASSET_LIST, assetType.shortName, ctx.session))) {
                        assetTypes.push({
                            url: this.buildBaseUrl(assetType.shortName) + '/list',
                            assetIcon: assetType.ui.icon || DEFAULT_ICON,
                            assetTitle: assetType.singularLabel
                        });
                    }
                }
                ribbon.currentType = page.rxt.singularLabel;
                ribbon.currentTitle = page.rxt.singularLabel;
                ribbon.currentUrl = this.buildBaseUrl(type) + '/list'; //page.meta.currentPage;
                ribbon.shortName = page.rxt.singularLabel;
                ribbon.query = 'Query';
                ribbon.breadcrumb = assetTypes;
                return page;
            },
            populateAttachedLifecycles: function(page) {
                if (page.assets.id) {
                    require('/modules/page-decorators.js').pageDecorators.populateAttachedLifecycles(ctx, page, this);
                }
            },
            populateAssetVersionDetails: function(page) {
                if (page.assets.id) {
                    require('/modules/page-decorators.js').pageDecorators.populateAssetVersionDetails(ctx, page, this);
                }
            },
            populateGroupingFeatureDetails: function(page) {
                require('/modules/page-decorators.js').pageDecorators.populateGroupingFeatureDetails(ctx, page);
            },
            populateTags: function(page){
                if(page.assets.id){
                    require('/modules/page-decorators.js').pageDecorators.populateTagDetails(ctx,page);
                }
            },
            sorting: function(page){
                require('/modules/page-decorators.js').pageDecorators.sorting(ctx,page);
            }
        }
    };
};
<|endoftext|>


<commit_before>CKEDITOR.editorConfig = function( config ) {
    config.toolbarGroups = [
        { name: 'clipboard',   groups: [ 'clipboard', 'undo' ] },
        { name: 'editing',     groups: [ 'find', 'selection', 'spellchecker' ] },
        { name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] },
        { name: 'paragraph',   groups: [ 'list', 'indent', 'blocks', 'align' ] },
        { name: 'styles' },
        { name: 'tools' },
    ];

    config.extraPlugins = 'citacao';
    config.allowedContent = true;

    config.toolbar_mini = [
        ['Bold', 'Italic', 'Underline', 'Subscript', 'Superscript', '-', 'RemoveFormat'],
        ['Maximize']
    ]
};
<commit_msg>CKEditor em português<commit_after>CKEDITOR.editorConfig = function( config ) {
    config.toolbarGroups = [
        { name: 'clipboard',   groups: [ 'clipboard', 'undo' ] },
        { name: 'editing',     groups: [ 'find', 'selection', 'spellchecker' ] },
        { name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] },
        { name: 'paragraph',   groups: [ 'list', 'indent', 'blocks', 'align' ] },
        { name: 'styles' },
        { name: 'tools' },
    ];

    config.extraPlugins = 'citacao';
    config.allowedContent = true;

    config.toolbar_mini = [
        ['Bold', 'Italic', 'Underline', 'Subscript', 'Superscript', '-', 'RemoveFormat'],
        ['Maximize']
    ];

    config.language = 'pt-br';
};
<|endoftext|>


<commit_before>// ===================================================================================================
//                           _  __     _ _
//                          | |/ /__ _| | |_ _  _ _ _ __ _
//                          | ' </ _` | |  _| || | '_/ _` |
//                          |_|\_\__,_|_|\__|\_,_|_| \__,_|
//
// This file is part of the Kaltura Collaborative Media Suite which allows users
// to do with audio, video, and animation what Wiki platfroms allow them to do with
// text.
//
// Copyright (C) 2006-2018  Kaltura Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// @ignore
// ===================================================================================================
/**
 * The Kaltura Client - this is the facade through which all service actions should be called.
 * @param config the Kaltura configuration object holding partner credentials (type: KalturaConfiguration).
 */
var util = require('util');
var kaltura = require('./KalturaClientBase');
kaltura.services = require('./KalturaServices');
kaltura.objects = require('./KalturaModel');
kaltura.enums = require('./KalturaTypes');

class Client extends kaltura.ClientBase {

	/**
	 * @param Configuration config
	 */
	constructor(config) {
		super(config);
		this.setApiVersion('14.2.0');
		this.setClientTag('node:18-07-17');
	}
}

module.exports = kaltura;
module.exports.Client = Client;

<commit_msg>New clientlib ver<commit_after>// ===================================================================================================
//                           _  __     _ _
//                          | |/ /__ _| | |_ _  _ _ _ __ _
//                          | ' </ _` | |  _| || | '_/ _` |
//                          |_|\_\__,_|_|\__|\_,_|_| \__,_|
//
// This file is part of the Kaltura Collaborative Media Suite which allows users
// to do with audio, video, and animation what Wiki platfroms allow them to do with
// text.
//
// Copyright (C) 2006-2018  Kaltura Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// @ignore
// ===================================================================================================
/**
 * The Kaltura Client - this is the facade through which all service actions should be called.
 * @param config the Kaltura configuration object holding partner credentials (type: KalturaConfiguration).
 */
var util = require('util');
var kaltura = require('./KalturaClientBase');
kaltura.services = require('./KalturaServices');
kaltura.objects = require('./KalturaModel');
kaltura.enums = require('./KalturaTypes');

class Client extends kaltura.ClientBase {

	/**
	 * @param Configuration config
	 */
	constructor(config) {
		super(config);
		this.setApiVersion('14.2.0');
		this.setClientTag('node:18-07-18');
	}
}

module.exports = kaltura;
module.exports.Client = Client;

<|endoftext|>