<commit_before>/*
 * Copyright 2013 The Polymer Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style
 * license that can be found in the LICENSE file.
 */
(function(scope) {

  // imports

  var extend = Polymer.extend;
  var apis = scope.api.declaration;

  // imperative implementation: Polymer()

  // maps tag names to prototypes
  var prototypesByName = {};

  function getRegisteredPrototype(name) {
    return prototypesByName[name];
  }

  // elements waiting for prototype, by name
  var waitPrototype = {};

  // specify an 'own' prototype for tag `name`
  function element(name, prototype) {
    //console.log('registering [' + name + ']');
    // cache the prototype
    prototypesByName[name] = prototype || {};
    // notify the registrar waiting for 'name', if any
    notifyPrototype(name);
  }

  function notifyPrototype(name) {
    if (waitPrototype[name]) {
      waitPrototype[name].registerWhenReady();
      delete waitPrototype[name];
    }
  }

  // elements waiting for super, by name
  var waitSuper = {};

  function notifySuper(name) {
    registered[name] = true;
    var waiting = waitSuper[name];
    if (waiting) {
      waiting.forEach(function(w) {
        w.registerWhenReady();
      });
      delete waitSuper[name];
    }
  }

  // track document.register'ed tag names

  var registered = {};

  function isRegistered(name) {
    return registered[name];
  }

  // returns a prototype that chains to <tag> or HTMLElement
  function generatePrototype(tag) {
    return Object.create(HTMLElement.getPrototypeForTag(tag));
  }

  // On platforms that do not support __proto__ (IE10), the prototype chain
  // of a custom element is simulated via installation of __proto__.
  // Although custom elements manages this, we install it here so it's
  // available during desugaring.
  function ensurePrototypeTraversal(prototype) {
    if (!Object.__proto__) {
      var ancestor = Object.getPrototypeOf(prototype);
      prototype.__proto__ = ancestor;
      if (scope.isBase(ancestor)) {
        ancestor.__proto__ = Object.getPrototypeOf(ancestor);
      }
    }
  }

  // declarative implementation: <polymer-element>

  var prototype = generatePrototype();

  extend(prototype, {
    // TODO(sjmiles): temporary BC
    readyCallback: function() {
      this.createdCallback();
    },
    createdCallback: function() {
      // fetch the element name
      this.name = this.getAttribute('name');
      // install element definition, if ready
      this.registerWhenReady();
    },
    registerWhenReady: function() {
      var name = this.name;
      // if we have no prototype
      if (!getRegisteredPrototype(name)) {
        // then wait for a prototype
        waitPrototype[name] = this;
        // TODO(sjmiles): there is a massive asynchrony between parsing
        // HTML in imports and executing script that foils this `async` gambit
        // Ideally the import polyfill has timing closer to the real deal; in
        // the meantime, invert the strategy and require `noscript` marking
        // instead.
        /*
        // if we are not explicitly async,
        // then wait for end of microtask(-ish)
        // and use whatever prototype is available
        if (!this.hasAttribute('async')) {
          setTimeout(function() {
            if (!getRegisteredPrototype(name)) {
              console.warn('giving up waiting for script for [' + name + ']');
              element(name, null);
            }
          }, 3000);
        }
        */
        if (this.hasAttribute('noscript')) {
          // go async so the parser can process the element's children before
          // registration
          setTimeout(function() {
            element(name, null);
          }, 0);
        }
        return;
      }
      // fetch our extendee name
      var extendee = this.getAttribute('extends');
      // if extending a custom element...
      if (extendee && extendee.indexOf('-') >= 0) {
        // wait for the extendee to be registered first
        if (!isRegistered(extendee)) {
          (waitSuper[extendee] = (waitSuper[extendee] || [])).push(this);
          return;
        }
      }
      // TODO(sjmiles): HTMLImports polyfill awareness
      if (document.contains(this) && window.HTMLImports && !HTMLImports.readyTime) {
        addEventListener('HTMLImportsLoaded', function() {
          this.register(name, extendee);
        }.bind(this));
      } else {
        this.register(name, extendee);
      }
    },
    register: function(name, extendee) {
      //console.log('register', name, extendee);
      // build prototype combining extendee, Polymer base, and named api
      this.prototype = this.generateCustomPrototype(name, extendee);
      // backref
      this.prototype.element = this;
      // TODO(sorvell): install a helper method this.resolvePath to aid in
      // setting resource paths. e.g.
      // this.$.image.src = this.resolvePath('images/foo.png')
      // Potentially remove when spec bug is addressed.
      // https://www.w3.org/Bugs/Public/show_bug.cgi?id=21407
      this.addResolvePathApi();
      ensurePrototypeTraversal(this.prototype);
      // declarative features
      this.desugar();
      // under ShadowDOMPolyfill, transforms to approximate missing CSS features
      if (window.ShadowDOMPolyfill) {
        Platform.ShadowCSS.shimStyling(this.templateContent(), name, extendee);
      }
      // register our custom element
      this.registerPrototype(name);
      // reference constructor in a global named by 'constructor' attribute
      this.publishConstructor();
      // subclasses may now register themselves
      notifySuper(name);
    },
    // implement various declarative features
    desugar: function(prototype) {
      // parse `attribute` attribute and `publish` object
      this.parseAttributes();
      // parse on-* delegates declared on `this` element
      this.parseHostEvents();
      // parse on-* delegates declared in templates
      this.parseLocalEvents();
      // install external stylesheets as if they are inline
      this.installSheets();
      // allow custom element access to the declarative context
      if (this.prototype.registerCallback) {
        this.prototype.registerCallback(this);
      }
      // cache the list of custom prototype names for faster reflection
      this.cacheProperties();
    },
    // prototype marshaling
    // build prototype combining extendee, Polymer base, and named api
    generateCustomPrototype: function (name, extnds) {
      // basal prototype
      var prototype = this.generateBasePrototype(extnds);
      // mixin registered custom api
      return this.addNamedApi(prototype, name);
    },
    // build prototype combining extendee, Polymer base, and named api
    generateBasePrototype: function(extnds) {
      // create a prototype based on tag-name extension
      var prototype = generatePrototype(extnds);
      // insert base api in inheritance chain (if needed)
      return this.ensureBaseApi(prototype);
    },
    // install Polymer instance api into prototype chain, as needed
    ensureBaseApi: function(prototype) {
      if (!prototype.PolymerBase) {
        Object.keys(scope.api.instance).forEach(function(n) {
          extend(prototype, scope.api.instance[n]);
        });
        prototype = Object.create(prototype);
      }
      // inherit publishing meta-data
      this.inheritAttributesObjects(prototype);
      // inherit event delegates
      this.inheritDelegates(prototype);
      // return buffed-up prototype
      return prototype;
    },
    // mix api registered to 'name' into 'prototype'
    addNamedApi: function(prototype, name) {
      // combine custom api into prototype
      return extend(prototype, getRegisteredPrototype(name));
    },
    // make a fresh object that inherits from a prototype object
    inheritObject: function(prototype, name) {
      // copy inherited properties onto a new object
      prototype[name] = extend({}, Object.getPrototypeOf(prototype)[name]);
    },
    // register 'prototype' to custom element 'name', store constructor
    registerPrototype: function(name) {
      // register the custom type
      this.ctor = document.register(name, {
        prototype: this.prototype
      });
      // constructor shenanigans
      this.prototype.constructor = this.ctor;
      // register the prototype with HTMLElement for name lookup
      HTMLElement.register(name, this.prototype);
    },
    // if a named constructor is requested in element, map a reference
    // to the constructor to the given symbol
    publishConstructor: function() {
      var symbol = this.getAttribute('constructor');
      if (symbol) {
        window[symbol] = this.ctor;
      }
    }
  });

  Object.keys(apis).forEach(function(n) {
    extend(prototype, apis[n]);
  });

  // register polymer-element with document

  document.register('polymer-element', {prototype: prototype});

  // namespace shenanigans so we can expose our scope on the registration function

  // TODO(sjmiles): find a way to do this that is less terrible
  // copy window.Polymer properties onto `element()`
  extend(element, scope);
  // make window.Polymer reference `element()`
  window.Polymer = element;

})(Polymer);
<commit_msg>restore 'async' flag instead of 'noscript' (will be removed directly because it doesn't actually work, putting it here so the code is tracked in source control)<commit_after>/*
 * Copyright 2013 The Polymer Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style
 * license that can be found in the LICENSE file.
 */
(function(scope) {

  // imports

  var extend = Polymer.extend;
  var apis = scope.api.declaration;

  // imperative implementation: Polymer()

  // maps tag names to prototypes
  var prototypesByName = {};

  function getRegisteredPrototype(name) {
    return prototypesByName[name];
  }

  // elements waiting for prototype, by name
  var waitPrototype = {};

  // specify an 'own' prototype for tag `name`
  function element(name, prototype) {
    //console.log('registering [' + name + ']');
    // cache the prototype
    prototypesByName[name] = prototype || {};
    // notify the registrar waiting for 'name', if any
    notifyPrototype(name);
  }

  function notifyPrototype(name) {
    if (waitPrototype[name]) {
      waitPrototype[name].registerWhenReady();
      delete waitPrototype[name];
    }
  }

  // elements waiting for super, by name
  var waitSuper = {};

  function notifySuper(name) {
    registered[name] = true;
    var waiting = waitSuper[name];
    if (waiting) {
      waiting.forEach(function(w) {
        w.registerWhenReady();
      });
      delete waitSuper[name];
    }
  }

  // track document.register'ed tag names

  var registered = {};

  function isRegistered(name) {
    return registered[name];
  }

  // returns a prototype that chains to <tag> or HTMLElement
  function generatePrototype(tag) {
    return Object.create(HTMLElement.getPrototypeForTag(tag));
  }

  // On platforms that do not support __proto__ (IE10), the prototype chain
  // of a custom element is simulated via installation of __proto__.
  // Although custom elements manages this, we install it here so it's
  // available during desugaring.
  function ensurePrototypeTraversal(prototype) {
    if (!Object.__proto__) {
      var ancestor = Object.getPrototypeOf(prototype);
      prototype.__proto__ = ancestor;
      if (scope.isBase(ancestor)) {
        ancestor.__proto__ = Object.getPrototypeOf(ancestor);
      }
    }
  }

  function whenImportsLoaded(doThis) {
    if (window.HTMLImports && !HTMLImports.readyTime) {
      addEventListener('HTMLImportsLoaded', doThis);
    } else {
      doThis();
    }
  }

  // declarative implementation: <polymer-element>

  var prototype = generatePrototype();

  extend(prototype, {
    // TODO(sjmiles): temporary BC
    readyCallback: function() {
      this.createdCallback();
    },
    createdCallback: function() {
      // fetch the element name
      this.name = this.getAttribute('name');
      // install element definition, if ready
      this.registerWhenReady();
    },
    registerWhenReady: function() {
      var name = this.name;
      // if we have no prototype
      if (!getRegisteredPrototype(name)) {
        // then wait for a prototype
        waitPrototype[name] = this;
        // if we are not explicitly async...
        if (!this.hasAttribute('async')) {
          // then we expect the script to be registered
          // by end of microtask(-ish) and can otherwise
          // consider this element to have no script
          //
          // TODO(sjmiles):
          // we have to wait for end-of-microtask because
          // native CE upgrades polymer-element (any custom
          // element, really) *before* it's children are
          // parsed, and it's common for the script to
          // exist as a child of the polymer-element
          //
          // additionally, there is a massive asynchrony
          // between parsing HTML in imports and executing
          // script that foils the end of microtask gambit
          // Waiting on HTMLImportsLoaded signal solves
          // both timing problems for imports loaded
          // at startup under the import polyfill
          whenImportsLoaded(function() {
            if (!getRegisteredPrototype(name)) {
              console.warn('giving up waiting for script for [' + name + ']');
              element(name, null);
            }
          });
        }
        return;
      }
      // fetch our extendee name
      var extendee = this.getAttribute('extends');
      // if extending a custom element...
      if (extendee && extendee.indexOf('-') >= 0) {
        // wait for the extendee to be registered first
        if (!isRegistered(extendee)) {
          (waitSuper[extendee] = (waitSuper[extendee] || [])).push(this);
          return;
        }
      }
      // TODO(sjmiles): HTMLImports polyfill awareness
      if (document.contains(this)) {
        whenImportsLoaded(function() {
          this.register(name, extendee);
        }.bind(this));
      } else {
        this.register(name, extendee);
      }
    },
    register: function(name, extendee) {
      //console.log('register', name, extendee);
      // build prototype combining extendee, Polymer base, and named api
      this.prototype = this.generateCustomPrototype(name, extendee);
      // backref
      this.prototype.element = this;
      // TODO(sorvell): install a helper method this.resolvePath to aid in
      // setting resource paths. e.g.
      // this.$.image.src = this.resolvePath('images/foo.png')
      // Potentially remove when spec bug is addressed.
      // https://www.w3.org/Bugs/Public/show_bug.cgi?id=21407
      this.addResolvePathApi();
      ensurePrototypeTraversal(this.prototype);
      // declarative features
      this.desugar();
      // under ShadowDOMPolyfill, transforms to approximate missing CSS features
      if (window.ShadowDOMPolyfill) {
        Platform.ShadowCSS.shimStyling(this.templateContent(), name, extendee);
      }
      // register our custom element
      this.registerPrototype(name);
      // reference constructor in a global named by 'constructor' attribute
      this.publishConstructor();
      // subclasses may now register themselves
      notifySuper(name);
    },
    // implement various declarative features
    desugar: function(prototype) {
      // parse `attribute` attribute and `publish` object
      this.parseAttributes();
      // parse on-* delegates declared on `this` element
      this.parseHostEvents();
      // parse on-* delegates declared in templates
      this.parseLocalEvents();
      // install external stylesheets as if they are inline
      this.installSheets();
      // allow custom element access to the declarative context
      if (this.prototype.registerCallback) {
        this.prototype.registerCallback(this);
      }
      // cache the list of custom prototype names for faster reflection
      this.cacheProperties();
    },
    // prototype marshaling
    // build prototype combining extendee, Polymer base, and named api
    generateCustomPrototype: function (name, extnds) {
      // basal prototype
      var prototype = this.generateBasePrototype(extnds);
      // mixin registered custom api
      return this.addNamedApi(prototype, name);
    },
    // build prototype combining extendee, Polymer base, and named api
    generateBasePrototype: function(extnds) {
      // create a prototype based on tag-name extension
      var prototype = generatePrototype(extnds);
      // insert base api in inheritance chain (if needed)
      return this.ensureBaseApi(prototype);
    },
    // install Polymer instance api into prototype chain, as needed
    ensureBaseApi: function(prototype) {
      if (!prototype.PolymerBase) {
        Object.keys(scope.api.instance).forEach(function(n) {
          extend(prototype, scope.api.instance[n]);
        });
        prototype = Object.create(prototype);
      }
      // inherit publishing meta-data
      this.inheritAttributesObjects(prototype);
      // inherit event delegates
      this.inheritDelegates(prototype);
      // return buffed-up prototype
      return prototype;
    },
    // mix api registered to 'name' into 'prototype'
    addNamedApi: function(prototype, name) {
      // combine custom api into prototype
      return extend(prototype, getRegisteredPrototype(name));
    },
    // make a fresh object that inherits from a prototype object
    inheritObject: function(prototype, name) {
      // copy inherited properties onto a new object
      prototype[name] = extend({}, Object.getPrototypeOf(prototype)[name]);
    },
    // register 'prototype' to custom element 'name', store constructor
    registerPrototype: function(name) {
      // register the custom type
      this.ctor = document.register(name, {
        prototype: this.prototype
      });
      // constructor shenanigans
      this.prototype.constructor = this.ctor;
      // register the prototype with HTMLElement for name lookup
      HTMLElement.register(name, this.prototype);
    },
    // if a named constructor is requested in element, map a reference
    // to the constructor to the given symbol
    publishConstructor: function() {
      var symbol = this.getAttribute('constructor');
      if (symbol) {
        window[symbol] = this.ctor;
      }
    }
  });

  Object.keys(apis).forEach(function(n) {
    extend(prototype, apis[n]);
  });

  // register polymer-element with document

  document.register('polymer-element', {prototype: prototype});

  // namespace shenanigans so we can expose our scope on the registration function

  // TODO(sjmiles): find a way to do this that is less terrible
  // copy window.Polymer properties onto `element()`
  extend(element, scope);
  // make window.Polymer reference `element()`
  window.Polymer = element;

})(Polymer);
<|endoftext|>


<commit_before>;(function (exports) { // nothing in here is node-specific.

// See http://semver.org/
// This implementation is a *hair* less strict in that it allows
// v1.2.3 things, and also tags that don't begin with a char.

var semver = "\\s*[v=]*\\s*([0-9]+)"                // major
           + "\\.([0-9]+)"                  // minor
           + "\\.([0-9]+)"                  // patch
           + "(-[0-9]+-?)?"                 // build
           + "([a-zA-Z-][a-zA-Z0-9-\.:]*)?" // tag
  , exprComparator = "^((<|>)?=?)\s*("+semver+")$|^$"
  , xRangePlain = "[v=]*([0-9]+|x|X|\\*)"
                + "(?:\\.([0-9]+|x|X|\\*)"
                + "(?:\\.([0-9]+|x|X|\\*)"
                + "([a-zA-Z-][a-zA-Z0-9-\.:]*)?)?)?"
  , xRange = "((?:<|>)=?)?\\s*" + xRangePlain
  , exprSpermy = "(?:~>?)"+xRange
  , expressions = exports.expressions =
    { parse : new RegExp("^\\s*"+semver+"\\s*$")
    , parsePackage : new RegExp("^\\s*([^\/]+)[-@](" +semver+")\\s*$")
    , parseRange : new RegExp(
        "^\\s*(" + semver + ")\\s+-\\s+(" + semver + ")\\s*$")
    , validComparator : new RegExp("^"+exprComparator+"$")
    , parseXRange : new RegExp("^"+xRange+"$")
    , parseSpermy : new RegExp("^"+exprSpermy+"$")
    }

Object.getOwnPropertyNames(expressions).forEach(function (i) {
  exports[i] = function (str) {
    return ("" + (str || "")).match(expressions[i])
  }
})

exports.rangeReplace = ">=$1 <=$7"
exports.clean = clean
exports.compare = compare
exports.rcompare = rcompare
exports.satisfies = satisfies
exports.gt = gt
exports.gte = gte
exports.lt = lt
exports.lte = lte
exports.eq = eq
exports.neq = neq
exports.cmp = cmp
exports.inc = inc

exports.valid = valid
exports.validPackage = validPackage
exports.validRange = validRange
exports.maxSatisfying = maxSatisfying

exports.replaceStars = replaceStars
exports.toComparators = toComparators

function stringify (version) {
  var v = version
  return [v[1]||'', v[2]||'', v[3]||''].join(".") + (v[4]||'') + (v[5]||'')
}

function clean (version) {
  version = exports.parse(version)
  if (!version) return version
  return stringify(version)
}

function valid (version) {
  if (typeof version !== "string") return null
  return exports.parse(version) && version.trim().replace(/^[v=]+/, '')
}

function validPackage (version) {
  if (typeof version !== "string") return null
  return version.match(expressions.parsePackage) && version.trim()
}

// range can be one of:
// "1.0.3 - 2.0.0" range, inclusive, like ">=1.0.3 <=2.0.0"
// ">1.0.2" like 1.0.3 - 9999.9999.9999
// ">=1.0.2" like 1.0.2 - 9999.9999.9999
// "<2.0.0" like 0.0.0 - 1.9999.9999
// ">1.0.2 <2.0.0" like 1.0.3 - 1.9999.9999
var starExpression = /(<|>)?=?\s*\*/g
  , starReplace = ""
  , compTrimExpression = new RegExp("((<|>)?=?)\\s*("
                                    +semver+"|"+xRangePlain+")", "g")
  , compTrimReplace = "$1$3"

function toComparators (range) {
  var ret = (range || "").trim()
    .replace(expressions.parseRange, exports.rangeReplace)
    .replace(compTrimExpression, compTrimReplace)
    .split(/\s+/)
    .join(" ")
    .split("||")
    .map(function (orchunk) {
      return orchunk
        .split(" ")
        .map(replaceXRanges)
        .map(replaceSpermies)
        .map(replaceStars)
        .join(" ").trim()
    })
    .map(function (orchunk) {
      return orchunk
        .trim()
        .split(/\s+/)
        .filter(function (c) { return c.match(expressions.validComparator) })
    })
    .filter(function (c) { return c.length })
  return ret
}

function replaceStars (stars) {
  return stars.trim().replace(starExpression, starReplace)
}

// "2.x","2.x.x" --> ">=2.0.0- <2.1.0-"
// "2.3.x" --> ">=2.3.0- <2.4.0-"
function replaceXRanges (ranges) {
  return ranges.split(/\s+/)
               .map(replaceXRange)
               .join(" ")
}

function replaceXRange (version) {
  return version.trim().replace(expressions.parseXRange,
                                function (v, gtlt, M, m, p, t) {
    var anyX = !M || M.toLowerCase() === "x" || M === "*"
               || !m || m.toLowerCase() === "x" || m === "*"
               || !p || p.toLowerCase() === "x" || p === "*"
      , ret = v

    if (gtlt && anyX) {
      // just replace x'es with zeroes
      ;(!M || M === "*" || M.toLowerCase() === "x") && (M = 0)
      ;(!m || m === "*" || m.toLowerCase() === "x") && (m = 0)
      ;(!p || p === "*" || p.toLowerCase() === "x") && (p = 0)
      ret = gtlt + M+"."+m+"."+p+"-"
    } else if (!M || M === "*" || M.toLowerCase() === "x") {
      ret = "*" // allow any
    } else if (!m || m === "*" || m.toLowerCase() === "x") {
      // append "-" onto the version, otherwise
      // "1.x.x" matches "2.0.0beta", since the tag
      // *lowers* the version value
      ret = ">="+M+".0.0- <"+(+M+1)+".0.0-"
    } else if (!p || p === "*" || p.toLowerCase() === "x") {
      ret = ">="+M+"."+m+".0- <"+M+"."+(+m+1)+".0-"
    }
    //console.error("parseXRange", [].slice.call(arguments), ret)
    return ret
  })
}

// ~, ~> --> * (any, kinda silly)
// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0 <3.0.0
// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0 <2.1.0
// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0
// ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0
// ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0
function replaceSpermies (version) {
  return version.trim().replace(expressions.parseSpermy,
                                function (v, gtlt, M, m, p, t) {
    if (gtlt) throw new Error(
      "Using '"+gtlt+"' with ~ makes no sense. Don't do it.")

    if (!M || M.toLowerCase() === "x") {
      return ""
    }
    // ~1 == >=1.0.0- <2.0.0-
    if (!m || m.toLowerCase() === "x") {
      return ">="+M+".0.0- <"+(+M+1)+".0.0-"
    }
    // ~1.2 == >=1.2.0- <1.3.0-
    if (!p || p.toLowerCase() === "x") {
      return ">="+M+"."+m+".0- <"+M+"."+(+m+1)+".0-"
    }
    // ~1.2.3 == >=1.2.3- <1.3.0-
    t = t || "-"
    return ">="+M+"."+m+"."+p+t+" <"+M+"."+(+m+1)+".0-"
  })
}

function validRange (range) {
  range = replaceStars(range)
  var c = toComparators(range)
  return (c.length === 0)
       ? null
       : c.map(function (c) { return c.join(" ") }).join("||")
}

// returns the highest satisfying version in the list, or undefined
function maxSatisfying (versions, range) {
  return versions
    .filter(function (v) { return satisfies(v, range) })
    .sort(compare)
    .pop()
}
function satisfies (version, range) {
  version = valid(version)
  if (!version) return false
  range = toComparators(range)
  for (var i = 0, l = range.length ; i < l ; i ++) {
    var ok = false
    for (var j = 0, ll = range[i].length ; j < ll ; j ++) {
      var r = range[i][j]
        , gtlt = r.charAt(0) === ">" ? gt
               : r.charAt(0) === "<" ? lt
               : false
        , eq = r.charAt(!!gtlt) === "="
        , sub = (!!eq) + (!!gtlt)
      if (!gtlt) eq = true
      r = r.substr(sub)
      r = (r === "") ? r : valid(r)
      ok = (r === "") || (eq && r === version) || (gtlt && gtlt(version, r))
      if (!ok) break
    }
    if (ok) return true
  }
  return false
}

// return v1 > v2 ? 1 : -1
function compare (v1, v2) {
  var g = gt(v1, v2)
  return g === null ? 0 : g ? 1 : -1
}

function rcompare (v1, v2) {
  return compare(v2, v1)
}

function lt (v1, v2) { return gt(v2, v1) }
function gte (v1, v2) { return !lt(v1, v2) }
function lte (v1, v2) { return !gt(v1, v2) }
function eq (v1, v2) { return gt(v1, v2) === null }
function neq (v1, v2) { return gt(v1, v2) !== null }
function cmp (v1, c, v2) {
  switch (c) {
    case ">": return gt(v1, v2)
    case "<": return lt(v1, v2)
    case ">=": return gte(v1, v2)
    case "<=": return lte(v1, v2)
    case "==": return eq(v1, v2)
    case "!=": return neq(v1, v2)
    case "===": return v1 === v2
    case "!==": return v1 !== v2
    default: throw new Error("Y U NO USE VALID COMPARATOR!? "+c)
  }
}

// return v1 > v2
function num (v) {
  return v === undefined ? -1 : parseInt((v||"0").replace(/[^0-9]+/g, ''), 10)
}
function gt (v1, v2) {
  v1 = exports.parse(v1)
  v2 = exports.parse(v2)
  if (!v1 || !v2) return false

  for (var i = 1; i < 5; i ++) {
    v1[i] = num(v1[i])
    v2[i] = num(v2[i])
    if (v1[i] > v2[i]) return true
    else if (v1[i] !== v2[i]) return false
  }
  // no tag is > than any tag, or use lexicographical order.
  var tag1 = v1[5] || ""
    , tag2 = v2[5] || ""

  // kludge: null means they were equal.  falsey, and detectable.
  // embarrassingly overclever, though, I know.
  return tag1 === tag2 ? null
         : !tag1 ? true
         : !tag2 ? false
         : tag1 > tag2
}

function inc (version, release) {
  version = exports.parse(version)
  if (!version) return null

  var parsedIndexLookup =
    { 'major': 1
    , 'minor': 2
    , 'patch': 3
    , 'build': 4 }
  var incIndex = parsedIndexLookup[release]
  if (incIndex === undefined) return null

  var current = num(version[incIndex])
  version[incIndex] = current === -1 ? 1 : current + 1

  for (var i = incIndex + 1; i < 5; i ++) {
    if (num(version[i]) !== -1) version[i] = "0"
  }

  if (version[4]) version[4] = "-" + version[4]
  version[5] = ""

  return stringify(version)
}
})(typeof exports === "object" ? exports : semver = {})
<commit_msg>spacing<commit_after>;(function (exports) { // nothing in here is node-specific.

// See http://semver.org/
// This implementation is a *hair* less strict in that it allows
// v1.2.3 things, and also tags that don't begin with a char.

var semver = "\\s*[v=]*\\s*([0-9]+)"        // major
           + "\\.([0-9]+)"                  // minor
           + "\\.([0-9]+)"                  // patch
           + "(-[0-9]+-?)?"                 // build
           + "([a-zA-Z-][a-zA-Z0-9-\.:]*)?" // tag
  , exprComparator = "^((<|>)?=?)\s*("+semver+")$|^$"
  , xRangePlain = "[v=]*([0-9]+|x|X|\\*)"
                + "(?:\\.([0-9]+|x|X|\\*)"
                + "(?:\\.([0-9]+|x|X|\\*)"
                + "([a-zA-Z-][a-zA-Z0-9-\.:]*)?)?)?"
  , xRange = "((?:<|>)=?)?\\s*" + xRangePlain
  , exprSpermy = "(?:~>?)"+xRange
  , expressions = exports.expressions =
    { parse : new RegExp("^\\s*"+semver+"\\s*$")
    , parsePackage : new RegExp("^\\s*([^\/]+)[-@](" +semver+")\\s*$")
    , parseRange : new RegExp(
        "^\\s*(" + semver + ")\\s+-\\s+(" + semver + ")\\s*$")
    , validComparator : new RegExp("^"+exprComparator+"$")
    , parseXRange : new RegExp("^"+xRange+"$")
    , parseSpermy : new RegExp("^"+exprSpermy+"$")
    }

Object.getOwnPropertyNames(expressions).forEach(function (i) {
  exports[i] = function (str) {
    return ("" + (str || "")).match(expressions[i])
  }
})

exports.rangeReplace = ">=$1 <=$7"
exports.clean = clean
exports.compare = compare
exports.rcompare = rcompare
exports.satisfies = satisfies
exports.gt = gt
exports.gte = gte
exports.lt = lt
exports.lte = lte
exports.eq = eq
exports.neq = neq
exports.cmp = cmp
exports.inc = inc

exports.valid = valid
exports.validPackage = validPackage
exports.validRange = validRange
exports.maxSatisfying = maxSatisfying

exports.replaceStars = replaceStars
exports.toComparators = toComparators

function stringify (version) {
  var v = version
  return [v[1]||'', v[2]||'', v[3]||''].join(".") + (v[4]||'') + (v[5]||'')
}

function clean (version) {
  version = exports.parse(version)
  if (!version) return version
  return stringify(version)
}

function valid (version) {
  if (typeof version !== "string") return null
  return exports.parse(version) && version.trim().replace(/^[v=]+/, '')
}

function validPackage (version) {
  if (typeof version !== "string") return null
  return version.match(expressions.parsePackage) && version.trim()
}

// range can be one of:
// "1.0.3 - 2.0.0" range, inclusive, like ">=1.0.3 <=2.0.0"
// ">1.0.2" like 1.0.3 - 9999.9999.9999
// ">=1.0.2" like 1.0.2 - 9999.9999.9999
// "<2.0.0" like 0.0.0 - 1.9999.9999
// ">1.0.2 <2.0.0" like 1.0.3 - 1.9999.9999
var starExpression = /(<|>)?=?\s*\*/g
  , starReplace = ""
  , compTrimExpression = new RegExp("((<|>)?=?)\\s*("
                                    +semver+"|"+xRangePlain+")", "g")
  , compTrimReplace = "$1$3"

function toComparators (range) {
  var ret = (range || "").trim()
    .replace(expressions.parseRange, exports.rangeReplace)
    .replace(compTrimExpression, compTrimReplace)
    .split(/\s+/)
    .join(" ")
    .split("||")
    .map(function (orchunk) {
      return orchunk
        .split(" ")
        .map(replaceXRanges)
        .map(replaceSpermies)
        .map(replaceStars)
        .join(" ").trim()
    })
    .map(function (orchunk) {
      return orchunk
        .trim()
        .split(/\s+/)
        .filter(function (c) { return c.match(expressions.validComparator) })
    })
    .filter(function (c) { return c.length })
  return ret
}

function replaceStars (stars) {
  return stars.trim().replace(starExpression, starReplace)
}

// "2.x","2.x.x" --> ">=2.0.0- <2.1.0-"
// "2.3.x" --> ">=2.3.0- <2.4.0-"
function replaceXRanges (ranges) {
  return ranges.split(/\s+/)
               .map(replaceXRange)
               .join(" ")
}

function replaceXRange (version) {
  return version.trim().replace(expressions.parseXRange,
                                function (v, gtlt, M, m, p, t) {
    var anyX = !M || M.toLowerCase() === "x" || M === "*"
               || !m || m.toLowerCase() === "x" || m === "*"
               || !p || p.toLowerCase() === "x" || p === "*"
      , ret = v

    if (gtlt && anyX) {
      // just replace x'es with zeroes
      ;(!M || M === "*" || M.toLowerCase() === "x") && (M = 0)
      ;(!m || m === "*" || m.toLowerCase() === "x") && (m = 0)
      ;(!p || p === "*" || p.toLowerCase() === "x") && (p = 0)
      ret = gtlt + M+"."+m+"."+p+"-"
    } else if (!M || M === "*" || M.toLowerCase() === "x") {
      ret = "*" // allow any
    } else if (!m || m === "*" || m.toLowerCase() === "x") {
      // append "-" onto the version, otherwise
      // "1.x.x" matches "2.0.0beta", since the tag
      // *lowers* the version value
      ret = ">="+M+".0.0- <"+(+M+1)+".0.0-"
    } else if (!p || p === "*" || p.toLowerCase() === "x") {
      ret = ">="+M+"."+m+".0- <"+M+"."+(+m+1)+".0-"
    }
    //console.error("parseXRange", [].slice.call(arguments), ret)
    return ret
  })
}

// ~, ~> --> * (any, kinda silly)
// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0 <3.0.0
// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0 <2.1.0
// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0
// ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0
// ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0
function replaceSpermies (version) {
  return version.trim().replace(expressions.parseSpermy,
                                function (v, gtlt, M, m, p, t) {
    if (gtlt) throw new Error(
      "Using '"+gtlt+"' with ~ makes no sense. Don't do it.")

    if (!M || M.toLowerCase() === "x") {
      return ""
    }
    // ~1 == >=1.0.0- <2.0.0-
    if (!m || m.toLowerCase() === "x") {
      return ">="+M+".0.0- <"+(+M+1)+".0.0-"
    }
    // ~1.2 == >=1.2.0- <1.3.0-
    if (!p || p.toLowerCase() === "x") {
      return ">="+M+"."+m+".0- <"+M+"."+(+m+1)+".0-"
    }
    // ~1.2.3 == >=1.2.3- <1.3.0-
    t = t || "-"
    return ">="+M+"."+m+"."+p+t+" <"+M+"."+(+m+1)+".0-"
  })
}

function validRange (range) {
  range = replaceStars(range)
  var c = toComparators(range)
  return (c.length === 0)
       ? null
       : c.map(function (c) { return c.join(" ") }).join("||")
}

// returns the highest satisfying version in the list, or undefined
function maxSatisfying (versions, range) {
  return versions
    .filter(function (v) { return satisfies(v, range) })
    .sort(compare)
    .pop()
}
function satisfies (version, range) {
  version = valid(version)
  if (!version) return false
  range = toComparators(range)
  for (var i = 0, l = range.length ; i < l ; i ++) {
    var ok = false
    for (var j = 0, ll = range[i].length ; j < ll ; j ++) {
      var r = range[i][j]
        , gtlt = r.charAt(0) === ">" ? gt
               : r.charAt(0) === "<" ? lt
               : false
        , eq = r.charAt(!!gtlt) === "="
        , sub = (!!eq) + (!!gtlt)
      if (!gtlt) eq = true
      r = r.substr(sub)
      r = (r === "") ? r : valid(r)
      ok = (r === "") || (eq && r === version) || (gtlt && gtlt(version, r))
      if (!ok) break
    }
    if (ok) return true
  }
  return false
}

// return v1 > v2 ? 1 : -1
function compare (v1, v2) {
  var g = gt(v1, v2)
  return g === null ? 0 : g ? 1 : -1
}

function rcompare (v1, v2) {
  return compare(v2, v1)
}

function lt (v1, v2) { return gt(v2, v1) }
function gte (v1, v2) { return !lt(v1, v2) }
function lte (v1, v2) { return !gt(v1, v2) }
function eq (v1, v2) { return gt(v1, v2) === null }
function neq (v1, v2) { return gt(v1, v2) !== null }
function cmp (v1, c, v2) {
  switch (c) {
    case ">": return gt(v1, v2)
    case "<": return lt(v1, v2)
    case ">=": return gte(v1, v2)
    case "<=": return lte(v1, v2)
    case "==": return eq(v1, v2)
    case "!=": return neq(v1, v2)
    case "===": return v1 === v2
    case "!==": return v1 !== v2
    default: throw new Error("Y U NO USE VALID COMPARATOR!? "+c)
  }
}

// return v1 > v2
function num (v) {
  return v === undefined ? -1 : parseInt((v||"0").replace(/[^0-9]+/g, ''), 10)
}
function gt (v1, v2) {
  v1 = exports.parse(v1)
  v2 = exports.parse(v2)
  if (!v1 || !v2) return false

  for (var i = 1; i < 5; i ++) {
    v1[i] = num(v1[i])
    v2[i] = num(v2[i])
    if (v1[i] > v2[i]) return true
    else if (v1[i] !== v2[i]) return false
  }
  // no tag is > than any tag, or use lexicographical order.
  var tag1 = v1[5] || ""
    , tag2 = v2[5] || ""

  // kludge: null means they were equal.  falsey, and detectable.
  // embarrassingly overclever, though, I know.
  return tag1 === tag2 ? null
         : !tag1 ? true
         : !tag2 ? false
         : tag1 > tag2
}

function inc (version, release) {
  version = exports.parse(version)
  if (!version) return null

  var parsedIndexLookup =
    { 'major': 1
    , 'minor': 2
    , 'patch': 3
    , 'build': 4 }
  var incIndex = parsedIndexLookup[release]
  if (incIndex === undefined) return null

  var current = num(version[incIndex])
  version[incIndex] = current === -1 ? 1 : current + 1

  for (var i = incIndex + 1; i < 5; i ++) {
    if (num(version[i]) !== -1) version[i] = "0"
  }

  if (version[4]) version[4] = "-" + version[4]
  version[5] = ""

  return stringify(version)
}
})(typeof exports === "object" ? exports : semver = {})
<|endoftext|>


<commit_before>// [INFO] See discussion of node.js exports here:
// https://www.sitepoint.com/understanding-module-exports-exports-node-js/

/**
 * Given a string `email`, return `true` if the string is in the form
 * of a valid Seneca College email address, `false` othewise.
 */
exports.isValidEmail = function (email) {
  return /^.*@myseneca\.ca$/.test(email);
};

/**
 * Given a string `name`, return a formatted Seneca email address for
 * this person. NOTE: the email doesn't need to be real/valid/active.
 */
exports.formatSenecaEmail = function (name) {
  return '${name}@myseneca.ca';
};
<commit_msg>fixed more erroes<commit_after>// [INFO] See discussion of node.js exports here:
// https://www.sitepoint.com/understanding-module-exports-exports-node-js/

/**
 * Given a string `email`, return `true` if the string is in the form
 * of a valid Seneca College email address, `false` othewise.
 */
exports.isValidEmail = function (email) {
  return /^.*@myseneca\.ca$/.test(email);
};

/**
 * Given a string `name`, return a formatted Seneca email address for
 * this person. NOTE: the email doesn't need to be real/valid/active.
 */
exports.formatSenecaEmail = function (name) {
  return `${name}@myseneca.ca`;
};
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2016-2022 Camptocamp SA
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

import angular from 'angular';
import {getUid as olUtilGetUid} from 'ol/util';
import {listen} from 'ol/events';
import ngeoMiscEventHelper from 'ngeo/misc/EventHelper';
import ngeoMiscDatetimepickerComponent from 'ngeo/misc/datetimepickerComponent';
import {ObjectEvent} from 'ol/Object';
import './editing.css';

/**
 * @type {angular.IModule}
 * @hidden
 */
const myModule = angular.module('ngeoAttributes', [
  ngeoMiscDatetimepickerComponent.name,
  ngeoMiscEventHelper.name,
]);

myModule.run(
  /**
   * @ngInject
   * @param {angular.ITemplateCacheService} $templateCache
   */
  ($templateCache) => {
    // @ts-ignore: webpack
    $templateCache.put('ngeo/editing/attributescomponent', require('./attributescomponent.html'));
  }
);

myModule.value(
  'ngeoAttributesTemplateUrl',
  /**
   * @param {angular.IAttributes} $attrs Attributes.
   * @returns {string} The template url.
   */
  ($attrs) => {
    const templateUrl = $attrs.ngeoAttributesTemplateUrl;
    return templateUrl !== undefined ? templateUrl : 'ngeo/editing/attributescomponent';
  }
);

/**
 * @param {angular.IAttributes} $attrs Attributes.
 * @param {function(angular.IAttributes): string} ngeoAttributesTemplateUrl Template function.
 * @returns {string} Template URL.
 * @ngInject
 * @private
 * @hidden
 */
function ngeoAttributesTemplateUrl($attrs, ngeoAttributesTemplateUrl) {
  return ngeoAttributesTemplateUrl($attrs);
}

/**
 * Component used to render the attributes of a feature into a form.
 * Example:
 *
 *     <ngeo-attributes
 *       ngeo-attributes-attributes="::ctrl.attributes"
 *       ngeo-attributes-disabled="ctrl.attributesDisabled"
 *       ngeo-attributes-feature="::ctrl.feature">
 *     </ngeo-attributes>
 *
 * @htmlAttribute {import('ngeo/format/Attribute').Attribute[]} ngeo-attributes-attributes The
 *     list of attributes to use.
 * @htmlAttribute {boolean} ngeo-attributes-disabled Whether the fieldset should
 *     be disabled or not.
 * @htmlAttribute {import('ol/Feature').default<import('ol/geom/Geometry').default>} ngeo-attributes-feature The feature.
 * @ngdoc component
 * @ngname ngeoAttributes
 */
const editingAttributeComponent = {
  controller: 'ngeoAttributesController as attrCtrl',
  bindings: {
    'attributes': '=ngeoAttributesAttributes',
    'disabled': '<ngeoAttributesDisabled',
    'feature': '=ngeoAttributesFeature',
  },
  require: {
    'form': '^',
  },
  templateUrl: ngeoAttributesTemplateUrl,
};

myModule.component('ngeoAttributes', editingAttributeComponent);

/**
 * @param {angular.IScope} $scope Angular scope.
 * @param {import('ngeo/misc/EventHelper').EventHelper} ngeoEventHelper Ngeo event helper service
 * @class
 * @hidden
 * @ngInject
 * @ngdoc controller
 * @ngname ngeoAttributesController
 */
export function Controller($scope, ngeoEventHelper) {
  /**
   * The list of attributes to create the form with.
   *
   * @type {import('ngeo/format/Attribute').Attribute[]}
   */
  this.attributes = [];

  /**
   * Whether the fieldset should be disabled or not.
   *
   * @type {boolean}
   */
  this.disabled = false;

  /**
   * The feature containing the values.
   *
   * @type {?import('ol/Feature').default<import('ol/geom/Geometry').default>}
   */
  this.feature = null;

  /**
   * The properties bound to the form, initialized with the inner properties
   * of the feature.
   *
   * @type {Object<string, *>}
   */
  this.properties = {};

  /**
   * @type {angular.IScope}
   */
  this.scope_ = $scope;

  /**
   * @type {import('ngeo/misc/EventHelper').EventHelper}
   */
  this.ngeoEventHelper_ = ngeoEventHelper;

  /**
   * While changes happen from the form (from the template), they are applied
   * to the feature inner properties. The 'propertychange' event registered
   * above does the opposite, i.e. it listens to the feature inner properties
   * changes and apply them to the form. To prevent circular issues, while
   * applying changes coming from the form, this flag is set. While set, changes
   * from the feature inner properties are ignored.
   *
   * @type {boolean}
   */
  this.updating_ = false;
}

/**
 * Initialise the component.
 */
Controller.prototype.$onInit = function () {
  if (!this.feature) {
    throw new Error('Missing feature');
  }
  this.properties = this.feature.getProperties();

  // Listen to the feature inner properties change and apply them to the form
  const uid = olUtilGetUid(this);

  // Set properties before starting to listen to changes to avoid multi AngularJS apply error.
  this.attributes.forEach((attribute) => {
    this.sanitize_(attribute);
    if (
      attribute.type === 'boolean' &&
      (this.feature.getProperties()[attribute.name] === null ||
        this.feature.getProperties()[attribute.name] === undefined)
    ) {
      this.feature.set(attribute.name, false);
    }
  });

  this.ngeoEventHelper_.addListenerKey(
    uid,
    listen(this.feature, 'propertychange', this.handleFeaturePropertyChange_, this)
  );
};

/**
 * Called when an input node value changes
 *
 * @param {string} name Attribute name
 */
Controller.prototype.handleInputChange = function (name) {
  if (!this.properties) {
    throw new Error('Missing properties');
  }
  if (!this.feature) {
    throw new Error('Missing feature');
  }
  this.updating_ = true;
  const attribute = this.attributes.find((attr) => attr.name === name);
  this.sanitize_(attribute);
  const value = this.properties[name];
  this.feature.set(name, value);
  this.updating_ = false;
};

/**
 * Never keep a undefined values, use null.
 * On boolean, replace null by false.
 * On date, datetime and time replace empty string by null.
 * @param {import('ngeo/format/Attribute.js').Attribute} attribute
 */
Controller.prototype.sanitize_ = function (attribute) {
  const value = this.properties[attribute.name];
  if (value === undefined) {
    this.properties[attribute.name] = null;
  }
  if (attribute.type === 'boolean' && value === null) {
    this.properties[attribute.name] = false;
  } else if (attribute.format && !value) {
    // Case of date, datetime or time.
    // Shouldn't be set to an empty string
    this.properties[attribute.name] = null;
  }
};

/**
 * Cleanup event listeners.
 */
Controller.prototype.$onDestroy = function () {
  const uid = olUtilGetUid(this);
  this.ngeoEventHelper_.clearListenerKey(uid);
};

/**
 * @param {Event|import('ol/events/Event').default} evt Event.
 */
Controller.prototype.handleFeaturePropertyChange_ = function (evt) {
  if (evt instanceof ObjectEvent) {
    if (this.updating_) {
      return;
    }
    // @ts-ignore
    this.properties[evt.key] = evt.target.get(evt.key);
    this.scope_.$apply();
  }
};

myModule.controller('ngeoAttributesController', Controller);

export default myModule;
<commit_msg>edition: Fix undefined boolean to false<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2016-2022 Camptocamp SA
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

import angular from 'angular';
import {getUid as olUtilGetUid} from 'ol/util';
import {listen} from 'ol/events';
import ngeoMiscEventHelper from 'ngeo/misc/EventHelper';
import ngeoMiscDatetimepickerComponent from 'ngeo/misc/datetimepickerComponent';
import {ObjectEvent} from 'ol/Object';
import './editing.css';

/**
 * @type {angular.IModule}
 * @hidden
 */
const myModule = angular.module('ngeoAttributes', [
  ngeoMiscDatetimepickerComponent.name,
  ngeoMiscEventHelper.name,
]);

myModule.run(
  /**
   * @ngInject
   * @param {angular.ITemplateCacheService} $templateCache
   */
  ($templateCache) => {
    // @ts-ignore: webpack
    $templateCache.put('ngeo/editing/attributescomponent', require('./attributescomponent.html'));
  }
);

myModule.value(
  'ngeoAttributesTemplateUrl',
  /**
   * @param {angular.IAttributes} $attrs Attributes.
   * @returns {string} The template url.
   */
  ($attrs) => {
    const templateUrl = $attrs.ngeoAttributesTemplateUrl;
    return templateUrl !== undefined ? templateUrl : 'ngeo/editing/attributescomponent';
  }
);

/**
 * @param {angular.IAttributes} $attrs Attributes.
 * @param {function(angular.IAttributes): string} ngeoAttributesTemplateUrl Template function.
 * @returns {string} Template URL.
 * @ngInject
 * @private
 * @hidden
 */
function ngeoAttributesTemplateUrl($attrs, ngeoAttributesTemplateUrl) {
  return ngeoAttributesTemplateUrl($attrs);
}

/**
 * Component used to render the attributes of a feature into a form.
 * Example:
 *
 *     <ngeo-attributes
 *       ngeo-attributes-attributes="::ctrl.attributes"
 *       ngeo-attributes-disabled="ctrl.attributesDisabled"
 *       ngeo-attributes-feature="::ctrl.feature">
 *     </ngeo-attributes>
 *
 * @htmlAttribute {import('ngeo/format/Attribute').Attribute[]} ngeo-attributes-attributes The
 *     list of attributes to use.
 * @htmlAttribute {boolean} ngeo-attributes-disabled Whether the fieldset should
 *     be disabled or not.
 * @htmlAttribute {import('ol/Feature').default<import('ol/geom/Geometry').default>} ngeo-attributes-feature The feature.
 * @ngdoc component
 * @ngname ngeoAttributes
 */
const editingAttributeComponent = {
  controller: 'ngeoAttributesController as attrCtrl',
  bindings: {
    'attributes': '=ngeoAttributesAttributes',
    'disabled': '<ngeoAttributesDisabled',
    'feature': '=ngeoAttributesFeature',
  },
  require: {
    'form': '^',
  },
  templateUrl: ngeoAttributesTemplateUrl,
};

myModule.component('ngeoAttributes', editingAttributeComponent);

/**
 * @param {angular.IScope} $scope Angular scope.
 * @param {import('ngeo/misc/EventHelper').EventHelper} ngeoEventHelper Ngeo event helper service
 * @class
 * @hidden
 * @ngInject
 * @ngdoc controller
 * @ngname ngeoAttributesController
 */
export function Controller($scope, ngeoEventHelper) {
  /**
   * The list of attributes to create the form with.
   *
   * @type {import('ngeo/format/Attribute').Attribute[]}
   */
  this.attributes = [];

  /**
   * Whether the fieldset should be disabled or not.
   *
   * @type {boolean}
   */
  this.disabled = false;

  /**
   * The feature containing the values.
   *
   * @type {?import('ol/Feature').default<import('ol/geom/Geometry').default>}
   */
  this.feature = null;

  /**
   * The properties bound to the form, initialized with the inner properties
   * of the feature.
   *
   * @type {Object<string, *>}
   */
  this.properties = {};

  /**
   * @type {angular.IScope}
   */
  this.scope_ = $scope;

  /**
   * @type {import('ngeo/misc/EventHelper').EventHelper}
   */
  this.ngeoEventHelper_ = ngeoEventHelper;

  /**
   * While changes happen from the form (from the template), they are applied
   * to the feature inner properties. The 'propertychange' event registered
   * above does the opposite, i.e. it listens to the feature inner properties
   * changes and apply them to the form. To prevent circular issues, while
   * applying changes coming from the form, this flag is set. While set, changes
   * from the feature inner properties are ignored.
   *
   * @type {boolean}
   */
  this.updating_ = false;
}

/**
 * Initialise the component.
 */
Controller.prototype.$onInit = function () {
  if (!this.feature) {
    throw new Error('Missing feature');
  }
  this.properties = this.feature.getProperties();

  // Listen to the feature inner properties change and apply them to the form
  const uid = olUtilGetUid(this);

  // Set properties before starting to listen to changes to avoid multi AngularJS apply error.
  this.attributes.forEach((attribute) => {
    this.sanitize_(attribute);
  });

  this.ngeoEventHelper_.addListenerKey(
    uid,
    listen(this.feature, 'propertychange', this.handleFeaturePropertyChange_, this)
  );
};

/**
 * Called when an input node value changes
 *
 * @param {string} name Attribute name
 */
Controller.prototype.handleInputChange = function (name) {
  if (!this.properties) {
    throw new Error('Missing properties');
  }
  if (!this.feature) {
    throw new Error('Missing feature');
  }
  this.updating_ = true;
  const attribute = this.attributes.find((attr) => attr.name === name);
  this.sanitize_(attribute);
  this.updating_ = false;
};

/**
 * Never keep a undefined values, use null.
 * On boolean, replace null by false.
 * On date, datetime and time replace empty string by null.
 * @param {import('ngeo/format/Attribute.js').Attribute} attribute
 */
Controller.prototype.sanitize_ = function (attribute) {
  let value = this.properties[attribute.name];
  if (value === undefined) {
    value = null;
  }
  if (attribute.type === 'boolean' && value === null) {
    value = false;
  } else if (attribute.format && !value) {
    // Case of date, datetime or time.
    // Shouldn't be set to an empty string
    value = null;
  }
  this.properties[attribute.name] = value;
  this.feature.set(attribute.name, value);
};

/**
 * Cleanup event listeners.
 */
Controller.prototype.$onDestroy = function () {
  const uid = olUtilGetUid(this);
  this.ngeoEventHelper_.clearListenerKey(uid);
};

/**
 * @param {Event|import('ol/events/Event').default} evt Event.
 */
Controller.prototype.handleFeaturePropertyChange_ = function (evt) {
  if (evt instanceof ObjectEvent) {
    if (this.updating_) {
      return;
    }
    // @ts-ignore
    this.properties[evt.key] = evt.target.get(evt.key);
    this.scope_.$apply();
  }
};

myModule.controller('ngeoAttributesController', Controller);

export default myModule;
<|endoftext|>


<commit_before>var image_cropping = {
  $: jQuery.noConflict(),
  init: function() {
    // set styles for size-warning
    var style_img_warning = 'div.jcrop-image.size-warning .jcrop-vline{border:1px solid red; background: none;}' +
                            'div.jcrop-image.size-warning .jcrop-hline{border:1px solid red; background: none;}';
    image_cropping.$("").appendTo('head');

    image_cropping.$('input.image-ratio').each(function() {
      var $this = image_cropping.$(this),
      // find the image field corresponding to this cropping value
      // by stripping the last part of our id and appending the image field name
          field = $this.attr('name').replace($this.data('my-name'), $this.data('image-field')),

      // there should only be one file field we're referencing but in special cases
      // there can be several. Deal with it gracefully.
          $image_input = image_cropping.$('input.crop-thumb[data-field-name=' + field + ']:first');

      // skip this image if it's empty and hide the whole field
      if (!$image_input.length || $image_input.data('thumbnail-url') == undefined) {
        $this.parents('div.form-row:first').hide();
        return;
      }
      var image_id = $this.attr('id') + '-image',
          org_width = $image_input.data('org-width'),
          org_height = $image_input.data('org-height'),
          min_width = $this.data('width'),
          min_height = $this.data('height');

      if ($this.data('adapt-rotation') == true) {
        if ($image.get(0).width < $image.get(0).height) {
          // cropping height/width need to be switched, picture is in portrait mode
          var x = min_width;
          min_width = min_height;
          min_height = x;
        }
      }

      var $image = image_cropping.$('', {
        'id': image_id,
        'src': $image_input.data('thumbnail-url')
      });

      var options = {
        aspectRatio: min_width/min_height,
        minSize: [5, 5],
        trueSize: [org_width, org_height],
        onSelect: image_cropping.update_selection($this),
        addClass: ($this.data('size-warning') && ((org_width < min_width) || (org_height < min_height))) ? 'size-warning jcrop-image': 'jcrop-image'
      }

      var cropping_disabled = false;
      if($this.val()[0] == "-"){
        cropping_disabled = true;
        $this.val($this.val().substr(1));
      }

      // is the image bigger than the minimal cropping values?
      // otherwise lock cropping area on full image
      var initial;
      if ($this.val()) {
        initial = image_cropping.initial_cropping($this.val());
      } else {

        initial = image_cropping.max_cropping(min_width, min_height, org_width, org_height);

          // set cropfield to initial value
        $this.val(initial.join(','));
      }

      image_cropping.$.extend(options, {setSelect: initial});

      // hide the input field, show image to crop instead
      $this.hide().after($image);

      image_cropping.$('#' + image_id).Jcrop(options, function(){jcrop=this;});

      if ($this.data('allow-fullsize') == true) {
        if(cropping_disabled){
          jcrop.release();
          $this.val('-'+$this.val());
        }
        var label = 'allow-fullsize-'+image_id;
        var checked = cropping_disabled ? ' checked="checked"' : '';
        image_cropping.$('
' +
                         '<input type="checkbox" id="'+label+'" name="'+label+'"'+checked+'>
').appendTo($this.parent());
        image_cropping.$('').appendTo('head');
        image_cropping.$('#'+label).click(function(){
          if (cropping_disabled==true){
            $this.val($this.val().substr(1));
            jcrop.setSelect($this.val().split(','));
            cropping_disabled = false;
          } else {
            $this.val('-'+$this.val());
            jcrop.release();
            cropping_disabled = true;
          }
        });
        $this.parent().find('.jcrop-tracker').mousedown(function(){
            image_cropping.$('#'+label).removeAttr("checked");
        });
      }
    });

    if (image_cropping.$('body').hasClass('change-form')) {
      // if we're in the Django admin, the holder needs to be floated
      // so it clears the label
      image_cropping.$("").appendTo('head');
    }
  },
  max_cropping: function(width, height, image_width, image_height) {
    var ratio = width/height;
    var offset;

    if (image_width < image_height * ratio) {
      // width fits fully, height needs to be cropped
      offset = Math.round((image_height-(image_width/ratio))/2);
      return [0, offset, image_width, image_height - offset];
    }
    // height fits fully, width needs to be cropped
    offset = Math.round((image_width-(image_height * ratio))/2);
    return [offset, 0, image_width - offset, image_height];
  },
  initial_cropping: function(val) {
    if (val == '') { return; }
    var s = val.split(',');
    return [
      parseInt(s[0], 10),
      parseInt(s[1], 10),
      parseInt(s[2], 10),
      parseInt(s[3], 10)
    ];
  },
  _update_selection: function(sel, $crop_field) {
    if ($crop_field.data('size-warning')) {
      image_cropping.crop_indication(sel, $crop_field);
    }
    $crop_field.val(new Array(
      sel.x,
      sel.y,
      sel.x2,
      sel.y2
    ).join(','));
  },
  update_selection: function($crop_field) {
    return function(sel) { image_cropping._update_selection(sel, $crop_field); };
  },
  crop_indication: function(sel, $crop_field) {
    // indicate if cropped area gets smaller than the specified minimal cropping
    var $jcrop_holder = $crop_field.siblings('.jcrop-holder');
    var min_width = $crop_field.data("width");
    var min_height = $crop_field.data("height");
    if ((sel.w < min_width) || (sel.h < min_height)) {
      $jcrop_holder.addClass('size-warning');
    } else {
      $jcrop_holder.removeClass('size-warning');
    }
  }
};
image_cropping.$(function() {image_cropping.init();});
<commit_msg>Swap checkbox behaviour<commit_after>var image_cropping = {
  $: jQuery.noConflict(),
  init: function() {
    // set styles for size-warning
    var style_img_warning = 'div.jcrop-image.size-warning .jcrop-vline{border:1px solid red; background: none;}' +
                            'div.jcrop-image.size-warning .jcrop-hline{border:1px solid red; background: none;}';
    image_cropping.$("").appendTo('head');

    image_cropping.$('input.image-ratio').each(function() {
      var $this = image_cropping.$(this),
      // find the image field corresponding to this cropping value
      // by stripping the last part of our id and appending the image field name
          field = $this.attr('name').replace($this.data('my-name'), $this.data('image-field')),

      // there should only be one file field we're referencing but in special cases
      // there can be several. Deal with it gracefully.
          $image_input = image_cropping.$('input.crop-thumb[data-field-name=' + field + ']:first');

      // skip this image if it's empty and hide the whole field
      if (!$image_input.length || $image_input.data('thumbnail-url') == undefined) {
        $this.parents('div.form-row:first').hide();
        return;
      }
      var image_id = $this.attr('id') + '-image',
          org_width = $image_input.data('org-width'),
          org_height = $image_input.data('org-height'),
          min_width = $this.data('width'),
          min_height = $this.data('height');

      if ($this.data('adapt-rotation') == true) {
        if ($image.get(0).width < $image.get(0).height) {
          // cropping height/width need to be switched, picture is in portrait mode
          var x = min_width;
          min_width = min_height;
          min_height = x;
        }
      }

      var $image = image_cropping.$('', {
        'id': image_id,
        'src': $image_input.data('thumbnail-url')
      });

      var options = {
        aspectRatio: min_width/min_height,
        minSize: [5, 5],
        trueSize: [org_width, org_height],
        onSelect: image_cropping.update_selection($this),
        addClass: ($this.data('size-warning') && ((org_width < min_width) || (org_height < min_height))) ? 'size-warning jcrop-image': 'jcrop-image'
      }

      var cropping_disabled = false;
      if($this.val()[0] == "-"){
        cropping_disabled = true;
        $this.val($this.val().substr(1));
      }

      // is the image bigger than the minimal cropping values?
      // otherwise lock cropping area on full image
      var initial;
      if ($this.val()) {
        initial = image_cropping.initial_cropping($this.val());
      } else {

        initial = image_cropping.max_cropping(min_width, min_height, org_width, org_height);

          // set cropfield to initial value
        $this.val(initial.join(','));
      }

      image_cropping.$.extend(options, {setSelect: initial});

      // hide the input field, show image to crop instead
      $this.hide().after($image);

      image_cropping.$('#' + image_id).Jcrop(options, function(){jcrop=this;});

      if ($this.data('allow-fullsize') == true) {
        if(cropping_disabled){
          jcrop.release();
          $this.val('-'+$this.val());
        }
        var label = 'allow-fullsize-'+image_id;
        var checked = cropping_disabled ? '' : ' checked="checked"';
        image_cropping.$('
' +
                         '<input type="checkbox" id="'+label+'" name="'+label+'"'+checked+'>
').appendTo($this.parent());
        image_cropping.$('').appendTo('head');
        image_cropping.$('#'+label).click(function(){
          if (cropping_disabled==true){
            $this.val($this.val().substr(1));
            jcrop.setSelect($this.val().split(','));
            cropping_disabled = false;
          } else {
            $this.val('-'+$this.val());
            jcrop.release();
            cropping_disabled = true;
          }
        });
        $this.parent().find('.jcrop-tracker').mousedown(function(){
            if (cropping_disabled){
              image_cropping.$('#'+label).attr('checked','checked')
              cropping_disabled = false;
            }
        });
      }
    });

    if (image_cropping.$('body').hasClass('change-form')) {
      // if we're in the Django admin, the holder needs to be floated
      // so it clears the label
      image_cropping.$("").appendTo('head');
    }
  },
  max_cropping: function(width, height, image_width, image_height) {
    var ratio = width/height;
    var offset;

    if (image_width < image_height * ratio) {
      // width fits fully, height needs to be cropped
      offset = Math.round((image_height-(image_width/ratio))/2);
      return [0, offset, image_width, image_height - offset];
    }
    // height fits fully, width needs to be cropped
    offset = Math.round((image_width-(image_height * ratio))/2);
    return [offset, 0, image_width - offset, image_height];
  },
  initial_cropping: function(val) {
    if (val == '') { return; }
    var s = val.split(',');
    return [
      parseInt(s[0], 10),
      parseInt(s[1], 10),
      parseInt(s[2], 10),
      parseInt(s[3], 10)
    ];
  },
  _update_selection: function(sel, $crop_field) {
    if ($crop_field.data('size-warning')) {
      image_cropping.crop_indication(sel, $crop_field);
    }
    $crop_field.val(new Array(
      sel.x,
      sel.y,
      sel.x2,
      sel.y2
    ).join(','));
  },
  update_selection: function($crop_field) {
    return function(sel) { image_cropping._update_selection(sel, $crop_field); };
  },
  crop_indication: function(sel, $crop_field) {
    // indicate if cropped area gets smaller than the specified minimal cropping
    var $jcrop_holder = $crop_field.siblings('.jcrop-holder');
    var min_width = $crop_field.data("width");
    var min_height = $crop_field.data("height");
    if ((sel.w < min_width) || (sel.h < min_height)) {
      $jcrop_holder.addClass('size-warning');
    } else {
      $jcrop_holder.removeClass('size-warning');
    }
  }
};
image_cropping.$(function() {image_cropping.init();});
<|endoftext|>


<commit_before>import { autorun, reaction } from 'mobx';

const debug = require('debug')('Franz:feature:spellchecker');

const DEFAULT_IS_PREMIUM_FEATURE = true;

export const config = {
  isPremiumFeature: DEFAULT_IS_PREMIUM_FEATURE,
};

export default function init(stores) {
  reaction(
    () => stores.features.features.needToWaitToProceed,
    (enabled, r) => {
      if (enabled) {
        debug('Initializing `spellchecker` feature');

        // Dispose the reaction to run this only once
        r.dispose();

        const { isSpellcheckerPremiumFeature } = stores.features.features;

        config.isPremiumFeature = isSpellcheckerPremiumFeature || DEFAULT_IS_PREMIUM_FEATURE;

        // reaction(
        //   () => stores.settings.all.app.enableSpellchecking,
        //   (enabled, r) => {
        //     if (enabled) {
        //       // debug('Initializing `spellchecker` feature');

        //       // // Dispose the reaction to run this only once
        //       // r.dispose();

        //       // const { isSpellcheckerPremiumFeature } = stores.features.features;

        //       // config.isPremiumFeature = isSpellcheckerPremiumFeature || DEFAULT_IS_PREMIUM_FEATURE;
        //     }
        //   },
        // );

        autorun(() => {
          if (!stores.user.data.isPremium && config.isPremiumFeature) {
            debug('Override settings.spellcheckerEnabled flag to false');

            Object.assign(stores.settings.all.app, {
              enableSpellchecker: false,
            });
          }
        });
      }
    },
  );
}

<commit_msg>Fix listening key<commit_after>import { autorun, reaction } from 'mobx';

const debug = require('debug')('Franz:feature:spellchecker');

const DEFAULT_IS_PREMIUM_FEATURE = true;

export const config = {
  isPremiumFeature: DEFAULT_IS_PREMIUM_FEATURE,
};

export default function init(stores) {
  reaction(
    () => stores.features.features.isSpellcheckerPremiumFeature,
    (enabled, r) => {
      if (enabled) {
        debug('Initializing `spellchecker` feature');

        // Dispose the reaction to run this only once
        r.dispose();

        const { isSpellcheckerPremiumFeature } = stores.features.features;

        config.isPremiumFeature = isSpellcheckerPremiumFeature || DEFAULT_IS_PREMIUM_FEATURE;

        autorun(() => {
          console.log('FEATURE spellchecker autorun', stores.user.data.isPremium, config.isPremiumFeature);
          if (!stores.user.data.isPremium && config.isPremiumFeature) {
            debug('Override settings.spellcheckerEnabled flag to false');

            Object.assign(stores.settings.all.app, {
              enableSpellchecker: false,
            });
          }
        });
      }
    },
  );
}

<|endoftext|>


<commit_before>import _ from 'lodash'
import selectorParser from 'postcss-selector-parser'
import postcss from 'postcss'
import substituteTailwindAtRules from '../lib/substituteTailwindAtRules'
import evaluateTailwindFunctions from '../lib/evaluateTailwindFunctions'
import substituteVariantsAtRules from '../lib/substituteVariantsAtRules'
import substituteResponsiveAtRules from '../lib/substituteResponsiveAtRules'
import convertLayerAtRulesToControlComments from '../lib/convertLayerAtRulesToControlComments'
import substituteScreenAtRules from '../lib/substituteScreenAtRules'
import prefixSelector from '../util/prefixSelector'
import { useMemo } from '../util/useMemo'

function hasAtRule(css, atRule) {
  let foundAtRule = false

  css.walkAtRules(atRule, () => {
    foundAtRule = true
    return false
  })

  return foundAtRule
}

function cloneWithoutChildren(node) {
  if (node.type === 'atrule') {
    return postcss.atRule({ name: node.name, params: node.params })
  }

  if (node.type === 'rule') {
    return postcss.rule({ name: node.name, selectors: node.selectors })
  }

  const clone = node.clone()
  clone.removeAll()
  return clone
}

const tailwindApplyPlaceholder = selectorParser.attribute({
  attribute: '__TAILWIND-APPLY-PLACEHOLDER__',
})

function generateRulesFromApply({ rule, utilityName: className, classPosition }, replaceWiths) {
  const parser = selectorParser(selectors => {
    let i = 0
    selectors.walkClasses(c => {
      if (classPosition === i++ && c.value === className) {
        c.replaceWith(tailwindApplyPlaceholder)
      }
    })
  })

  const processedSelectors = _.flatMap(rule.selectors, selector => {
    // You could argue we should make this replacement at the AST level, but if we believe
    // the placeholder string is safe from collisions then it is safe to do this is a simple
    // string replacement, and much, much faster.
    return replaceWiths.map(replaceWith =>
      parser.processSync(selector).replace('[__TAILWIND-APPLY-PLACEHOLDER__]', replaceWith)
    )
  })

  const cloned = rule.clone()
  let current = cloned
  let parent = rule.parent

  while (parent && parent.type !== 'root') {
    const parentClone = cloneWithoutChildren(parent)

    parentClone.append(current)
    current.parent = parentClone
    current = parentClone
    parent = parent.parent
  }

  cloned.selectors = processedSelectors
  return current
}

const extractUtilityNamesParser = selectorParser(selectors => {
  let classes = []
  selectors.walkClasses(c => classes.push(c.value))
  return classes
})

const extractUtilityNames = useMemo(
  selector => extractUtilityNamesParser.transformSync(selector),
  selector => selector
)

const cloneRuleWithParent = useMemo(
  rule => rule.clone({ parent: rule.parent }),
  rule => rule
)

function buildUtilityMap(css, lookupTree) {
  let index = 0
  const utilityMap = {}

  lookupTree.walkRules(rule => {
    const utilityNames = extractUtilityNames(rule.selector)

    utilityNames.forEach((utilityName, i) => {
      if (utilityMap[utilityName] === undefined) {
        utilityMap[utilityName] = []
      }

      utilityMap[utilityName].push({
        index,
        utilityName,
        classPosition: i,
        get rule() {
          return cloneRuleWithParent(rule)
        },
      })
      index++
    })
  })

  css.walkRules(rule => {
    const utilityNames = extractUtilityNames(rule.selector)

    utilityNames.forEach((utilityName, i) => {
      if (utilityMap[utilityName] === undefined) {
        utilityMap[utilityName] = []
      }

      utilityMap[utilityName].push({
        index,
        utilityName,
        classPosition: i,
        get rule() {
          return cloneRuleWithParent(rule)
        },
      })
      index++
    })
  })

  return utilityMap
}

function mergeAdjacentRules(initialRule, rulesToInsert) {
  let previousRule = initialRule

  rulesToInsert.forEach(toInsert => {
    if (
      toInsert.type === 'rule' &&
      previousRule.type === 'rule' &&
      toInsert.selector === previousRule.selector
    ) {
      previousRule.append(toInsert.nodes)
    } else if (
      toInsert.type === 'atrule' &&
      previousRule.type === 'atrule' &&
      toInsert.params === previousRule.params
    ) {
      const merged = mergeAdjacentRules(
        previousRule.nodes[previousRule.nodes.length - 1],
        toInsert.nodes
      )

      previousRule.append(merged)
    } else {
      previousRule = toInsert
    }

    toInsert.walk(n => {
      if (n.nodes && n.nodes.length === 0) {
        n.remove()
      }
    })
  })

  return rulesToInsert.filter(r => r.nodes.length > 0)
}

function makeExtractUtilityRules(css, lookupTree, config) {
  const utilityMap = buildUtilityMap(css, lookupTree)

  return function extractUtilityRules(utilityNames, rule) {
    const combined = []

    utilityNames.forEach(utilityName => {
      if (utilityMap[utilityName] === undefined) {
        // Look for prefixed utility in case the user has goofed
        const prefixedUtility = prefixSelector(config.prefix, `.${utilityName}`).slice(1)

        if (utilityMap[prefixedUtility] !== undefined) {
          throw rule.error(
            `The \`${utilityName}\` class does not exist, but \`${prefixedUtility}\` does. Did you forget the prefix?`
          )
        }

        throw rule.error(
          `The \`${utilityName}\` class does not exist. If you're sure that \`${utilityName}\` exists, make sure that any \`@import\` statements are being properly processed before Tailwind CSS sees your CSS, as \`@apply\` can only be used for classes in the same CSS tree.`,
          { word: utilityName }
        )
      }

      combined.push(...utilityMap[utilityName])
    })

    return combined.sort((a, b) => a.index - b.index)
  }
}

function processApplyAtRules(css, lookupTree, config) {
  const extractUtilityRules = makeExtractUtilityRules(css, lookupTree, config)

  do {
    css.walkRules(rule => {
      const applyRules = []

      // Only walk direct children to avoid issues with nesting plugins
      rule.each(child => {
        if (child.type === 'atrule' && child.name === 'apply') {
          applyRules.unshift(child)
        }
      })

      applyRules.forEach(applyRule => {
        const [
          importantEntries,
          applyUtilityNames,
          important = importantEntries.length > 0,
        ] = _.partition(applyRule.params.split(/[\s\t\n]+/g), n => n === '!important')

        const currentUtilityNames = extractUtilityNames(rule.selector)

        if (_.intersection(applyUtilityNames, currentUtilityNames).length > 0) {
          const currentUtilityName = _.intersection(applyUtilityNames, currentUtilityNames)[0]
          throw rule.error(
            `You cannot \`@apply\` the \`${currentUtilityName}\` utility here because it creates a circular dependency.`
          )
        }

        // Extract any post-apply declarations and re-insert them after apply rules
        const afterRule = rule.clone({ raws: {} })
        afterRule.nodes = afterRule.nodes.slice(rule.index(applyRule) + 1)
        rule.nodes = rule.nodes.slice(0, rule.index(applyRule) + 1)

        // Sort applys to match CSS source order
        const applys = extractUtilityRules(applyUtilityNames, applyRule)

        // Get new rules with the utility portion of the selector replaced with the new selector
        const rulesToInsert = [
          ...applys.map(applyUtility => {
            return generateRulesFromApply(applyUtility, rule.selectors)
          }),
          afterRule,
        ]

        const { nodes } = _.tap(postcss.root({ nodes: rulesToInsert }), root =>
          root.walkDecls(d => (d.important = important))
        )

        const mergedRules = mergeAdjacentRules(rule, nodes)

        applyRule.remove()
        rule.after(mergedRules)
      })

      // If the base rule has nothing in it (all applys were pseudo or responsive variants),
      // remove the rule fuggit.
      if (rule.nodes.length === 0) {
        rule.remove()
      }
    })

    // We already know that we have at least 1 @apply rule. Otherwise this
    // function would not have been called. Therefore we can execute this code
    // at least once. This also means that in the best case scenario we only
    // call this 2 times, instead of 3 times.
    // 1st time -> before we call this function
    // 2nd time -> when we check if we have to do this loop again (because do {} while (check))
    // .. instead of
    // 1st time -> before we call this function
    // 2nd time -> when we check the first time (because while (check) do {})
    // 3rd time -> when we re-check to see if we should do this loop again
  } while (hasAtRule(css, 'apply'))

  return css
}

let defaultTailwindTree = null

export default function applyComplexClasses(config, getProcessedPlugins, configChanged) {
  return function(css) {
    // We can stop already when we don't have any @apply rules. Vue users: you're welcome!
    if (!hasAtRule(css, 'apply')) {
      return css
    }

    // Tree already contains @tailwind rules, don't prepend default Tailwind tree
    if (hasAtRule(css, 'tailwind')) {
      return processApplyAtRules(css, postcss.root(), config)
    }

    // Tree contains no @tailwind rules, so generate all of Tailwind's styles and
    // prepend them to the user's CSS. Important for <style> blocks in Vue components.
    const generateLookupTree =
      configChanged || defaultTailwindTree === null
        ? () => {
            return postcss([
              substituteTailwindAtRules(config, getProcessedPlugins()),
              evaluateTailwindFunctions(config),
              substituteVariantsAtRules(config, getProcessedPlugins()),
              substituteResponsiveAtRules(config),
              convertLayerAtRulesToControlComments(config),
              substituteScreenAtRules(config),
            ])
              .process(
                `
                  @tailwind base;
                  @tailwind components;
                  @tailwind utilities;
                `,
                { from: undefined }
              )
              .then(result => {
                defaultTailwindTree = result
                return defaultTailwindTree
              })
          }
        : () => Promise.resolve(defaultTailwindTree)

    return generateLookupTree().then(result => {
      return processApplyAtRules(css, result.root, config)
    })
  }
}
<commit_msg>Don't return when updating declaration important<commit_after>import _ from 'lodash'
import selectorParser from 'postcss-selector-parser'
import postcss from 'postcss'
import substituteTailwindAtRules from '../lib/substituteTailwindAtRules'
import evaluateTailwindFunctions from '../lib/evaluateTailwindFunctions'
import substituteVariantsAtRules from '../lib/substituteVariantsAtRules'
import substituteResponsiveAtRules from '../lib/substituteResponsiveAtRules'
import convertLayerAtRulesToControlComments from '../lib/convertLayerAtRulesToControlComments'
import substituteScreenAtRules from '../lib/substituteScreenAtRules'
import prefixSelector from '../util/prefixSelector'
import { useMemo } from '../util/useMemo'

function hasAtRule(css, atRule) {
  let foundAtRule = false

  css.walkAtRules(atRule, () => {
    foundAtRule = true
    return false
  })

  return foundAtRule
}

function cloneWithoutChildren(node) {
  if (node.type === 'atrule') {
    return postcss.atRule({ name: node.name, params: node.params })
  }

  if (node.type === 'rule') {
    return postcss.rule({ name: node.name, selectors: node.selectors })
  }

  const clone = node.clone()
  clone.removeAll()
  return clone
}

const tailwindApplyPlaceholder = selectorParser.attribute({
  attribute: '__TAILWIND-APPLY-PLACEHOLDER__',
})

function generateRulesFromApply({ rule, utilityName: className, classPosition }, replaceWiths) {
  const parser = selectorParser(selectors => {
    let i = 0
    selectors.walkClasses(c => {
      if (classPosition === i++ && c.value === className) {
        c.replaceWith(tailwindApplyPlaceholder)
      }
    })
  })

  const processedSelectors = _.flatMap(rule.selectors, selector => {
    // You could argue we should make this replacement at the AST level, but if we believe
    // the placeholder string is safe from collisions then it is safe to do this is a simple
    // string replacement, and much, much faster.
    return replaceWiths.map(replaceWith =>
      parser.processSync(selector).replace('[__TAILWIND-APPLY-PLACEHOLDER__]', replaceWith)
    )
  })

  const cloned = rule.clone()
  let current = cloned
  let parent = rule.parent

  while (parent && parent.type !== 'root') {
    const parentClone = cloneWithoutChildren(parent)

    parentClone.append(current)
    current.parent = parentClone
    current = parentClone
    parent = parent.parent
  }

  cloned.selectors = processedSelectors
  return current
}

const extractUtilityNamesParser = selectorParser(selectors => {
  let classes = []
  selectors.walkClasses(c => classes.push(c.value))
  return classes
})

const extractUtilityNames = useMemo(
  selector => extractUtilityNamesParser.transformSync(selector),
  selector => selector
)

const cloneRuleWithParent = useMemo(
  rule => rule.clone({ parent: rule.parent }),
  rule => rule
)

function buildUtilityMap(css, lookupTree) {
  let index = 0
  const utilityMap = {}

  lookupTree.walkRules(rule => {
    const utilityNames = extractUtilityNames(rule.selector)

    utilityNames.forEach((utilityName, i) => {
      if (utilityMap[utilityName] === undefined) {
        utilityMap[utilityName] = []
      }

      utilityMap[utilityName].push({
        index,
        utilityName,
        classPosition: i,
        get rule() {
          return cloneRuleWithParent(rule)
        },
      })
      index++
    })
  })

  css.walkRules(rule => {
    const utilityNames = extractUtilityNames(rule.selector)

    utilityNames.forEach((utilityName, i) => {
      if (utilityMap[utilityName] === undefined) {
        utilityMap[utilityName] = []
      }

      utilityMap[utilityName].push({
        index,
        utilityName,
        classPosition: i,
        get rule() {
          return cloneRuleWithParent(rule)
        },
      })
      index++
    })
  })

  return utilityMap
}

function mergeAdjacentRules(initialRule, rulesToInsert) {
  let previousRule = initialRule

  rulesToInsert.forEach(toInsert => {
    if (
      toInsert.type === 'rule' &&
      previousRule.type === 'rule' &&
      toInsert.selector === previousRule.selector
    ) {
      previousRule.append(toInsert.nodes)
    } else if (
      toInsert.type === 'atrule' &&
      previousRule.type === 'atrule' &&
      toInsert.params === previousRule.params
    ) {
      const merged = mergeAdjacentRules(
        previousRule.nodes[previousRule.nodes.length - 1],
        toInsert.nodes
      )

      previousRule.append(merged)
    } else {
      previousRule = toInsert
    }

    toInsert.walk(n => {
      if (n.nodes && n.nodes.length === 0) {
        n.remove()
      }
    })
  })

  return rulesToInsert.filter(r => r.nodes.length > 0)
}

function makeExtractUtilityRules(css, lookupTree, config) {
  const utilityMap = buildUtilityMap(css, lookupTree)

  return function extractUtilityRules(utilityNames, rule) {
    const combined = []

    utilityNames.forEach(utilityName => {
      if (utilityMap[utilityName] === undefined) {
        // Look for prefixed utility in case the user has goofed
        const prefixedUtility = prefixSelector(config.prefix, `.${utilityName}`).slice(1)

        if (utilityMap[prefixedUtility] !== undefined) {
          throw rule.error(
            `The \`${utilityName}\` class does not exist, but \`${prefixedUtility}\` does. Did you forget the prefix?`
          )
        }

        throw rule.error(
          `The \`${utilityName}\` class does not exist. If you're sure that \`${utilityName}\` exists, make sure that any \`@import\` statements are being properly processed before Tailwind CSS sees your CSS, as \`@apply\` can only be used for classes in the same CSS tree.`,
          { word: utilityName }
        )
      }

      combined.push(...utilityMap[utilityName])
    })

    return combined.sort((a, b) => a.index - b.index)
  }
}

function processApplyAtRules(css, lookupTree, config) {
  const extractUtilityRules = makeExtractUtilityRules(css, lookupTree, config)

  do {
    css.walkRules(rule => {
      const applyRules = []

      // Only walk direct children to avoid issues with nesting plugins
      rule.each(child => {
        if (child.type === 'atrule' && child.name === 'apply') {
          applyRules.unshift(child)
        }
      })

      applyRules.forEach(applyRule => {
        const [
          importantEntries,
          applyUtilityNames,
          important = importantEntries.length > 0,
        ] = _.partition(applyRule.params.split(/[\s\t\n]+/g), n => n === '!important')

        const currentUtilityNames = extractUtilityNames(rule.selector)

        if (_.intersection(applyUtilityNames, currentUtilityNames).length > 0) {
          const currentUtilityName = _.intersection(applyUtilityNames, currentUtilityNames)[0]
          throw rule.error(
            `You cannot \`@apply\` the \`${currentUtilityName}\` utility here because it creates a circular dependency.`
          )
        }

        // Extract any post-apply declarations and re-insert them after apply rules
        const afterRule = rule.clone({ raws: {} })
        afterRule.nodes = afterRule.nodes.slice(rule.index(applyRule) + 1)
        rule.nodes = rule.nodes.slice(0, rule.index(applyRule) + 1)

        // Sort applys to match CSS source order
        const applys = extractUtilityRules(applyUtilityNames, applyRule)

        // Get new rules with the utility portion of the selector replaced with the new selector
        const rulesToInsert = [
          ...applys.map(applyUtility => {
            return generateRulesFromApply(applyUtility, rule.selectors)
          }),
          afterRule,
        ]

        const { nodes } = _.tap(postcss.root({ nodes: rulesToInsert }), root =>
          root.walkDecls(d => {
            d.important = important
          })
        )

        const mergedRules = mergeAdjacentRules(rule, nodes)

        applyRule.remove()
        rule.after(mergedRules)
      })

      // If the base rule has nothing in it (all applys were pseudo or responsive variants),
      // remove the rule fuggit.
      if (rule.nodes.length === 0) {
        rule.remove()
      }
    })

    // We already know that we have at least 1 @apply rule. Otherwise this
    // function would not have been called. Therefore we can execute this code
    // at least once. This also means that in the best case scenario we only
    // call this 2 times, instead of 3 times.
    // 1st time -> before we call this function
    // 2nd time -> when we check if we have to do this loop again (because do {} while (check))
    // .. instead of
    // 1st time -> before we call this function
    // 2nd time -> when we check the first time (because while (check) do {})
    // 3rd time -> when we re-check to see if we should do this loop again
  } while (hasAtRule(css, 'apply'))

  return css
}

let defaultTailwindTree = null

export default function applyComplexClasses(config, getProcessedPlugins, configChanged) {
  return function(css) {
    // We can stop already when we don't have any @apply rules. Vue users: you're welcome!
    if (!hasAtRule(css, 'apply')) {
      return css
    }

    // Tree already contains @tailwind rules, don't prepend default Tailwind tree
    if (hasAtRule(css, 'tailwind')) {
      return processApplyAtRules(css, postcss.root(), config)
    }

    // Tree contains no @tailwind rules, so generate all of Tailwind's styles and
    // prepend them to the user's CSS. Important for <style> blocks in Vue components.
    const generateLookupTree =
      configChanged || defaultTailwindTree === null
        ? () => {
            return postcss([
              substituteTailwindAtRules(config, getProcessedPlugins()),
              evaluateTailwindFunctions(config),
              substituteVariantsAtRules(config, getProcessedPlugins()),
              substituteResponsiveAtRules(config),
              convertLayerAtRulesToControlComments(config),
              substituteScreenAtRules(config),
            ])
              .process(
                `
                  @tailwind base;
                  @tailwind components;
                  @tailwind utilities;
                `,
                { from: undefined }
              )
              .then(result => {
                defaultTailwindTree = result
                return defaultTailwindTree
              })
          }
        : () => Promise.resolve(defaultTailwindTree)

    return generateLookupTree().then(result => {
      return processApplyAtRules(css, result.root, config)
    })
  }
}
<|endoftext|>


<commit_before>import React from 'react'
import * as d3 from 'd3'
import Faux from 'react-faux-dom'
import {connect} from 'react-redux'
import moment from 'moment'

const Chronos = React.createClass({
  mixins: [Faux.mixins.core, Faux.mixins.anim],

  getInitialState () {
    return {
      chart: 'loading...'
    }
  },

  componentWillMount() {
    this.repeatTimeout()
  },

  componentWillUnmount() {
    //noinspection Eslint
    clearTimeout(this.repeat)
  },

  repeatTimeout() {
    const context = this
    //noinspection Eslint
    this.repeat = setTimeout(function () {
      context.rescale();
      context.repeatTimeout(context);
    }, 5000)
  },

  componentDidMount () {
    var component = this
    var wrapper = this.refs.wrapper
    const faux = this.connectFauxDOM('div.renderedD3', 'chart')

    var margin = {top: 30, right: 0, bottom: 10, left: 0};
    var width = wrapper.clientWidth - margin.left - margin.right;
    var height = wrapper.clientHeight - margin.top - margin.bottom;

    var svg = d3.select(faux)
      .append('svg')
      .attr('width', width + margin.left + margin.right)
      .attr('height', height + margin.top + margin.bottom)
      .append('g')
      .attr('transform', 'translate(' + margin.left + ', ' + margin.top + ')');

    svg.append('rect')
      .attr('width', width)
      .attr('height', height)
      .style('fill', 'lightblue')
      .style('stroke', 'green');

    var start = moment().subtract(1, 'm')
    var end = moment().add(1, 'm')
    var xScale = d3.scaleTime()
      .domain([start.toDate(), end.toDate()])
      .range([0, width]);

    var xAxis = d3.axisTop(xScale).ticks(30)

    var axisComponent = svg.append('g')
      .attr("class", "xaxis")
      .call(xAxis);

    this.rescale = function () {
      var start = moment().subtract(1, 'm')
      var end = moment().add(1, 'm')
      var domain = [start.toDate(), end.toDate()]
      xScale.domain(domain)
      axisComponent.transition()
        .duration(1500)
        .ease(d3.easeSinOut).call(xAxis);

      component.animateFauxDOM(800)
    }
  },

  render () {
    return (
{this.state.chart}
)
  }
})

export default connect()(Chronos)<commit_msg>Handle resize / scalling<commit_after>import React from 'react'
import * as d3 from 'd3'
import Faux from 'react-faux-dom'
import {connect} from 'react-redux'
import moment from 'moment'

const Chronos = React.createClass({
  mixins: [Faux.mixins.core, Faux.mixins.anim],

  getInitialState () {
    return {
      chart: 'loading...'
    }
  },

  componentWillMount() {
    this.repeatTimeout()
  },

  componentWillUnmount() {
    //noinspection Eslint
    clearTimeout(this.repeat)
  },

  repeatTimeout() {
    const context = this
    //noinspection Eslint
    this.repeat = setTimeout(function () {
      context.rescale();
      context.repeatTimeout(context);
    }, 5000)
  },

  componentDidMount () {
    var component = this
    var wrapper = this.refs.wrapper
    const faux = this.connectFauxDOM('div.renderedD3', 'chart')

    var margin = {top: 10, right: 0, bottom: 10, left: 0};
    var width = wrapper.clientWidth - margin.left - margin.right;
    var height = wrapper.clientHeight - margin.top - margin.bottom;
    var aspect = wrapper.clientWidth / wrapper.clientHeight

    var svg = d3.select(faux).append('svg')
    var svgContainer = svg
      .attr('width', width + margin.left + margin.right)
      .attr('height', height + margin.top + margin.bottom)
      .call((currentContainer) => {
        currentContainer
          .attr("viewBox", "0 0 " + width + " " + height)
          .attr("preserveAspectRatio", "xMinYMid")
      })
      .append('g')
      .attr('transform', 'translate(' + margin.left + ', ' + margin.top + ')')

    svgContainer.append('rect')
      .attr('width', width)
      .attr('height', height)
      .style('fill', 'lightblue')
      .style('stroke', 'green')

    var start = moment().subtract(1, 'm')
    var end = moment().add(1, 'm')
    var xScale = d3.scaleTime()
      .domain([start.toDate(), end.toDate()])
      .range([0, width])

    var xAxis = d3.axisTop(xScale).ticks(30)

    var axisComponent = svgContainer.append('g')
      .attr("class", "xaxis")
      .call(xAxis);

    this.rescale = () => {
      var start = moment().subtract(1, 'm')
      var end = moment().add(1, 'm')
      var domain = [start.toDate(), end.toDate()]
      xScale.domain(domain)
      axisComponent.transition().duration(1500).ease(d3.easeSinOut).call(xAxis);
      component.animateFauxDOM(800)
    }

    window.addEventListener('resize', () => {
      var width = wrapper.clientWidth - margin.left - margin.right;
      var height = wrapper.clientHeight - margin.top - margin.bottom;
      svg.attr('width', width + margin.left + margin.right).attr('height', height + margin.top + margin.bottom)
      svg.attr("height", Math.round(width / aspect));
      component.animateFauxDOM(800)
    })
  },

  render () {
    return (
{this.state.chart}
)
  }
})

export default connect()(Chronos)<|endoftext|>


<commit_before>'use strict';
// Requiring collections-online and loading configuration
const co = require('./collections-online');
co.config(__dirname);
// Register collections-online plugins
require('./plugins').register();

// Creating an express app
const express = require('express');
const app = express();

co.initialize(app).then(() => {
  require('./routes')(app);
  co.registerRoutes(app);
  co.registerErrors(app);
}).then(null, console.error);
<commit_msg>Adds static hosting from node<commit_after>'use strict';
// Requiring collections-online and loading configuration
const co = require('./collections-online');
co.config(__dirname);
// Register collections-online plugins
require('./plugins').register();

// Creating an express app
const express = require('express');
const app = express();

app.use(express.static('generated'));

co.initialize(app).then(() => {
  require('./routes')(app);
  co.registerRoutes(app);
  co.registerErrors(app);
}).then(null, console.error);
<|endoftext|>