<commit_before>/** @namespace * */
var XML3D = XML3D || {};

/** @define {string} */
XML3D.version = '%VERSION%';
/** @const */
XML3D.xml3dNS = 'http://www.xml3d.org/2009/xml3d';
/** @const */
XML3D.xhtmlNS = 'http://www.w3.org/1999/xhtml';
/** @const */
XML3D.webglNS = 'http://www.xml3d.org/2009/xml3d/webgl';
XML3D._xml3d = document.createElementNS(XML3D.xml3dNS, "xml3d");
XML3D._native = !!XML3D._xml3d.style;
XML3D._parallel = XML3D._parallel != undefined ? XML3D._parallel : false;

XML3D.createElement = function(tagName) {
    return document.createElementNS(XML3D.xml3dNS, tagName);
};

XML3D.extend = function(a, b) {
    for ( var prop in b) {
        var g = b.__lookupGetter__(prop), s = b.__lookupSetter__(prop);
        if (g||s) {
            if (g) {
                a.__defineGetter__(prop, g);
            }
            if (s) {
                a.__defineSetter__(prop, s);
            }
        } else {
            if (b[prop] === undefined) {
                delete a[prop];
            } else if (prop !== "constructor" || a !== window) {
                a[prop] = b[prop];
            }
        }
    }
    return a;
};

/**
 * Returns true if ctor is a superclass of subclassCtor.
 * @param ctor
 * @param subclassCtor
 * @return {Boolean}
 */
XML3D.isSuperclassOf = function(ctor, subclassCtor) {
    while (subclassCtor && subclassCtor.superclass) {
        if (subclassCtor.superclass === ctor.prototype)
            return true;
        subclassCtor = subclassCtor.superclass.constructor;
    }
    return false;
}

/**
 *
 * @param {Object} ctor Constructor
 * @param {Object} parent Parent class
 * @param {Object=} methods Methods to add to the class
 * @return {Object!}
 */
XML3D.createClass = function(ctor, parent, methods) {
    methods = methods || {};
    if (parent) {
        /** @constructor */
        var F = function() {
        };
        F.prototype = parent.prototype;
        ctor.prototype = new F();
        ctor.prototype.constructor = ctor;
        ctor.superclass = parent.prototype;
    }
    ctor.isSuperclassOf = XML3D.isSuperclassOf.bind(ctor, ctor);
    for ( var m in methods) {
        ctor.prototype[m] = methods[m];
    }
    return ctor;
};

(function() {
    function displayWebGLNotSupportedInfo(xml3dElement){

        if(xml3dElement.hasAttribute("onunsupported")){
            var callback = new Function("event", xml3dElement.getAttribute("onunsupported"));
            xml3dElement.addEventListener('unsupported', callback, false);
        }
        var doDefault = XML3D.util.dispatchCustomEvent(xml3dElement, 'unsupported', false, true, null);
        if(doDefault){
            // Place xml3dElement inside an invisible div
            var hideDiv = document.createElementNS(XML3D.xhtmlNS, 'div');

            xml3dElement.parentNode.insertBefore(hideDiv, xml3dElement);
            hideDiv.appendChild(xml3dElement);
            hideDiv.style.display = "none";

            var infoDiv = document.createElementNS(XML3D.xhtmlNS, 'div');
            if(xml3dElement.hasAttribute("class")){
                infoDiv.setAttribute("class", xml3dElement.getAttribute("class"));
            }

            infoDiv.setAttribute("style", xml3dElement.getAttribute("style"));
            infoDiv.style.border = "2px solid red";
            infoDiv.style.color = "red";
            infoDiv.style.padding = "10px";
            infoDiv.style.backgroundColor = "rgba(255, 0, 0, 0.3)";

            var width = xml3dElement.getAttribute("width");
            if (width !== null) {
                infoDiv.style.width = width;
            }

            var height = xml3dElement.getAttribute("height");
            if (height !== null) {
                infoDiv.style.height = height;
            }

            var hElement = document.createElement("h3");
            var hTxt = document.createTextNode("Your browser doesn't appear to support XML3D.");
            hElement.appendChild(hTxt);

            var pElement = document.createElement("p");
            pElement.appendChild(document.createTextNode("Please visit "));
            var link = document.createElement("a");
            link.setAttribute("href", "http://www.xml3d.org");
            link.appendChild(document.createTextNode("http://www.xml3d.org"));
            pElement.appendChild(link);
            pElement.appendChild(document.createTextNode(" to get information about browsers supporting XML3D."));
            infoDiv.appendChild(hElement);
            infoDiv.appendChild(pElement);

            hideDiv.parentNode.insertBefore(infoDiv, hideDiv);
        }

    };

    /*  a list of elements that are currently initialized. More specifically,
     *  they're currently in a call to the method below.
     *
     *  Why?
     *  In webgl we actually reattach the xml3d element in the DOM. Thus, when
     *  we're in the middle of working on a onNodeInserted event, there will probably
     *  come right another event which we actually don't care for.
     *  So we use this list to keep track of which elements are currently initializing.
     */
    var curXML3DInitElements = [];

    /**
     * @param {Element} xml3dElement
     */
    function initXML3DElement(xml3dElement) {

        if (XML3D._native)
            return;

        if(-1 < curXML3DInitElements.indexOf(xml3dElement))
            return;

        curXML3DInitElements.push(xml3dElement);

        var debug = XML3D.debug.setup();

        if (!(XML3D.webgl && XML3D.webgl.supported())) {
            debug && XML3D.debug.logWarning("Could not initialise WebGL, sorry :-(");
            displayWebGLNotSupportedInfo(xml3dElement);
            curXML3DInitElements.splice(curXML3DInitElements.indexOf(xml3dElement), 1);
            return;
        }

        XML3D.debug.logInfo("Configuring", xml3dElement.querySelectorAll("*").length, "elements");

        try {
            XML3D.config.configure(xml3dElement);
        } catch (e) {
            debug && XML3D.debug.logException(e);
            curXML3DInitElements.splice(curXML3DInitElements.indexOf(xml3dElement), 1);
            return;
        }
        try {
            XML3D.webgl.configure(xml3dElement);
        } catch (e) {
            debug && XML3D.debug.logException(e);
            curXML3DInitElements.splice(curXML3DInitElements.indexOf(xml3dElement), 1);
            return;
        }

        // initialize all attached adapters
        XML3D.base.sendAdapterEvent(xml3dElement, {onConfigured : []});

        curXML3DInitElements.splice(curXML3DInitElements.indexOf(xml3dElement), 1);
    };

    /**
     * @param {Element} xml3dElement
     */
    function destroyXML3DElement(xml3dElement)
    {
        if(-1 < curXML3DInitElements.indexOf(xml3dElement))
            return;

        xml3dElement._configured = undefined;

        if(!xml3dElement.parentNode)
            return; // already removed

        var canvas = xml3dElement.parentNode.previousElementSibling;

        var grandParentNode = xml3dElement.parentNode.parentNode;
        if(!grandParentNode)
            return; // subtree containing canvas is not attached, can't remove it

        if(!canvas || canvas.tagName !== "canvas")
            return; // an element we didn't create, skip deletion

        grandParentNode.removeChild(xml3dElement.parentNode);
        grandParentNode.removeChild(canvas);
    };

    /**
     * @param {Event} evt
     */
    function onNodeInserted(evt) {

        if(evt.target.tagName === "xml3d") {
            initXML3DElement(evt.target);
        }
    };

    /**
     * @param {Event} evt
     */
    function onNodeRemoved(evt) {

        if(evt.target.tagName === "xml3d") {
            destroyXML3DElement(evt.target);
        }
    };

    function onLoad() {

        XML3D.options.setOptionsFromQuery();

        XML3D.css.init();

        var debug = XML3D.debug.setup();
        debug && XML3D.debug.logInfo("xml3d.js version: " + XML3D.version);

        /**
         * Find all the XML3D tags in the document
         * @type {NodeList}
         */
        var xml3ds = document.querySelectorAll("xml3d");

        debug && XML3D.debug.logInfo("Found " + xml3ds.length + " xml3d node(s)");

        if (xml3ds.length && XML3D._native) {
            debug && XML3D.debug.logInfo("Using native implementation.");
            return;
        }

        XML3D.xhtml = (document.xmlEncoding != null);

        for(var i = 0; i < xml3ds.length; i++) {
            initXML3DElement(xml3ds[i]);
        }
    };

    function onUnload() {
        if (XML3D.document)
            XML3D.document.onunload();
    };

    document.addEventListener('DOMContentLoaded', onLoad, false);
    window.addEventListener('unload', onUnload, false);
    window.addEventListener('reload', onUnload, false);
    document.addEventListener('DOMNodeInserted', onNodeInserted, false);
    document.addEventListener('DOMNodeRemoved', onNodeRemoved, false);

})();
<commit_msg>Prevent ios mobiles browser's DOM parser to transform numbers to telephone number links.<commit_after>/** @namespace * */
var XML3D = XML3D || {};

/** @define {string} */
XML3D.version = '%VERSION%';
/** @const */
XML3D.xml3dNS = 'http://www.xml3d.org/2009/xml3d';
/** @const */
XML3D.xhtmlNS = 'http://www.w3.org/1999/xhtml';
/** @const */
XML3D.webglNS = 'http://www.xml3d.org/2009/xml3d/webgl';
XML3D._xml3d = document.createElementNS(XML3D.xml3dNS, "xml3d");
XML3D._native = !!XML3D._xml3d.style;
XML3D._parallel = XML3D._parallel != undefined ? XML3D._parallel : false;

(function () {
    if (navigator.userAgent.match(/(iPad|iPhone|iPod touch)/i)) {
        var m = document.createElement("meta");
        m.name = "format-detection";
        m.content = "telephone=no";
        document.head.appendChild(m)
    }
}());

XML3D.createElement = function(tagName) {
    return document.createElementNS(XML3D.xml3dNS, tagName);
};

XML3D.extend = function(a, b) {
    for ( var prop in b) {
        var g = b.__lookupGetter__(prop), s = b.__lookupSetter__(prop);
        if (g||s) {
            if (g) {
                a.__defineGetter__(prop, g);
            }
            if (s) {
                a.__defineSetter__(prop, s);
            }
        } else {
            if (b[prop] === undefined) {
                delete a[prop];
            } else if (prop !== "constructor" || a !== window) {
                a[prop] = b[prop];
            }
        }
    }
    return a;
};

/**
 * Returns true if ctor is a superclass of subclassCtor.
 * @param ctor
 * @param subclassCtor
 * @return {Boolean}
 */
XML3D.isSuperclassOf = function(ctor, subclassCtor) {
    while (subclassCtor && subclassCtor.superclass) {
        if (subclassCtor.superclass === ctor.prototype)
            return true;
        subclassCtor = subclassCtor.superclass.constructor;
    }
    return false;
}

/**
 *
 * @param {Object} ctor Constructor
 * @param {Object} parent Parent class
 * @param {Object=} methods Methods to add to the class
 * @return {Object!}
 */
XML3D.createClass = function(ctor, parent, methods) {
    methods = methods || {};
    if (parent) {
        /** @constructor */
        var F = function() {
        };
        F.prototype = parent.prototype;
        ctor.prototype = new F();
        ctor.prototype.constructor = ctor;
        ctor.superclass = parent.prototype;
    }
    ctor.isSuperclassOf = XML3D.isSuperclassOf.bind(ctor, ctor);
    for ( var m in methods) {
        ctor.prototype[m] = methods[m];
    }
    return ctor;
};

(function() {
    function displayWebGLNotSupportedInfo(xml3dElement){

        if(xml3dElement.hasAttribute("onunsupported")){
            var callback = new Function("event", xml3dElement.getAttribute("onunsupported"));
            xml3dElement.addEventListener('unsupported', callback, false);
        }
        var doDefault = XML3D.util.dispatchCustomEvent(xml3dElement, 'unsupported', false, true, null);
        if(doDefault){
            // Place xml3dElement inside an invisible div
            var hideDiv = document.createElementNS(XML3D.xhtmlNS, 'div');

            xml3dElement.parentNode.insertBefore(hideDiv, xml3dElement);
            hideDiv.appendChild(xml3dElement);
            hideDiv.style.display = "none";

            var infoDiv = document.createElementNS(XML3D.xhtmlNS, 'div');
            if(xml3dElement.hasAttribute("class")){
                infoDiv.setAttribute("class", xml3dElement.getAttribute("class"));
            }

            infoDiv.setAttribute("style", xml3dElement.getAttribute("style"));
            infoDiv.style.border = "2px solid red";
            infoDiv.style.color = "red";
            infoDiv.style.padding = "10px";
            infoDiv.style.backgroundColor = "rgba(255, 0, 0, 0.3)";

            var width = xml3dElement.getAttribute("width");
            if (width !== null) {
                infoDiv.style.width = width;
            }

            var height = xml3dElement.getAttribute("height");
            if (height !== null) {
                infoDiv.style.height = height;
            }

            var hElement = document.createElement("h3");
            var hTxt = document.createTextNode("Your browser doesn't appear to support XML3D.");
            hElement.appendChild(hTxt);

            var pElement = document.createElement("p");
            pElement.appendChild(document.createTextNode("Please visit "));
            var link = document.createElement("a");
            link.setAttribute("href", "http://www.xml3d.org");
            link.appendChild(document.createTextNode("http://www.xml3d.org"));
            pElement.appendChild(link);
            pElement.appendChild(document.createTextNode(" to get information about browsers supporting XML3D."));
            infoDiv.appendChild(hElement);
            infoDiv.appendChild(pElement);

            hideDiv.parentNode.insertBefore(infoDiv, hideDiv);
        }

    };

    /*  a list of elements that are currently initialized. More specifically,
     *  they're currently in a call to the method below.
     *
     *  Why?
     *  In webgl we actually reattach the xml3d element in the DOM. Thus, when
     *  we're in the middle of working on a onNodeInserted event, there will probably
     *  come right another event which we actually don't care for.
     *  So we use this list to keep track of which elements are currently initializing.
     */
    var curXML3DInitElements = [];

    /**
     * @param {Element} xml3dElement
     */
    function initXML3DElement(xml3dElement) {

        if (XML3D._native)
            return;

        if(-1 < curXML3DInitElements.indexOf(xml3dElement))
            return;

        curXML3DInitElements.push(xml3dElement);

        var debug = XML3D.debug.setup();

        if (!(XML3D.webgl && XML3D.webgl.supported())) {
            debug && XML3D.debug.logWarning("Could not initialise WebGL, sorry :-(");
            displayWebGLNotSupportedInfo(xml3dElement);
            curXML3DInitElements.splice(curXML3DInitElements.indexOf(xml3dElement), 1);
            return;
        }

        XML3D.debug.logInfo("Configuring", xml3dElement.querySelectorAll("*").length, "elements");

        try {
            XML3D.config.configure(xml3dElement);
        } catch (e) {
            debug && XML3D.debug.logException(e);
            curXML3DInitElements.splice(curXML3DInitElements.indexOf(xml3dElement), 1);
            return;
        }
        try {
            XML3D.webgl.configure(xml3dElement);
        } catch (e) {
            debug && XML3D.debug.logException(e);
            curXML3DInitElements.splice(curXML3DInitElements.indexOf(xml3dElement), 1);
            return;
        }

        // initialize all attached adapters
        XML3D.base.sendAdapterEvent(xml3dElement, {onConfigured : []});

        curXML3DInitElements.splice(curXML3DInitElements.indexOf(xml3dElement), 1);
    };

    /**
     * @param {Element} xml3dElement
     */
    function destroyXML3DElement(xml3dElement)
    {
        if(-1 < curXML3DInitElements.indexOf(xml3dElement))
            return;

        xml3dElement._configured = undefined;

        if(!xml3dElement.parentNode)
            return; // already removed

        var canvas = xml3dElement.parentNode.previousElementSibling;

        var grandParentNode = xml3dElement.parentNode.parentNode;
        if(!grandParentNode)
            return; // subtree containing canvas is not attached, can't remove it

        if(!canvas || canvas.tagName !== "canvas")
            return; // an element we didn't create, skip deletion

        grandParentNode.removeChild(xml3dElement.parentNode);
        grandParentNode.removeChild(canvas);
    };

    /**
     * @param {Event} evt
     */
    function onNodeInserted(evt) {

        if(evt.target.tagName === "xml3d") {
            initXML3DElement(evt.target);
        }
    };

    /**
     * @param {Event} evt
     */
    function onNodeRemoved(evt) {

        if(evt.target.tagName === "xml3d") {
            destroyXML3DElement(evt.target);
        }
    };

    function onLoad() {

        XML3D.options.setOptionsFromQuery();

        XML3D.css.init();

        var debug = XML3D.debug.setup();
        debug && XML3D.debug.logInfo("xml3d.js version: " + XML3D.version);

        /**
         * Find all the XML3D tags in the document
         * @type {NodeList}
         */
        var xml3ds = document.querySelectorAll("xml3d");

        debug && XML3D.debug.logInfo("Found " + xml3ds.length + " xml3d node(s)");

        if (xml3ds.length && XML3D._native) {
            debug && XML3D.debug.logInfo("Using native implementation.");
            return;
        }

        XML3D.xhtml = (document.xmlEncoding != null);

        for(var i = 0; i < xml3ds.length; i++) {
            initXML3DElement(xml3ds[i]);
        }
    };

    function onUnload() {
        if (XML3D.document)
            XML3D.document.onunload();
    };

    document.addEventListener('DOMContentLoaded', onLoad, false);
    window.addEventListener('unload', onUnload, false);
    window.addEventListener('reload', onUnload, false);
    document.addEventListener('DOMNodeInserted', onNodeInserted, false);
    document.addEventListener('DOMNodeRemoved', onNodeRemoved, false);

})();
<|endoftext|>


<commit_before>Taskar.Sections.Tasks = {
  click: {
    '.cancel': function(e, element){
      e.findElement('li').slideUp();
    },
    '.delete': function(e, element){
      e.stop();
      element.request({
        method: 'delete',
        onComplete: function(){
          element.up('.task').removeWithEffect('slideUp');
        }
      });
    },
    '.checkbox': Taskar.UI.StateCheckboxObserver
  },
  'state:changed': function(e) {
    var checkbox = e.findElement('.checkbox');
    if (checkbox){
      new Ajax.Request(checkbox.getAttribute('data-url'), {
        method:     'put',
        parameters: {state: checkbox.getAttribute('data-state')}
      });
    }
  }
};
<commit_msg>don't wait for server to response to remove the task from the screen<commit_after>Taskar.Sections.Tasks = {
  click: {
    '.cancel': function(e, element){
      e.findElement('li').slideUp();
    },
    '.delete': function(e, element){
      e.stop();
      element.request({
        method: 'delete',
        onCreate: function(){
          element.up('.task').removeWithEffect('slideUp');
        }
      });
    },
    '.checkbox': Taskar.UI.StateCheckboxObserver
  },
  'state:changed': function(e) {
    var checkbox = e.findElement('.checkbox');
    if (checkbox){
      new Ajax.Request(checkbox.getAttribute('data-url'), {
        method:     'put',
        parameters: {state: checkbox.getAttribute('data-state')}
      });
    }
  }
};
<|endoftext|>


<commit_before>/*
 * Copyright 2014 Thoughtworks Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
define([
    'flight/lib/component',
    'component/mixins/with_auth_token_from_hash',
  ],
  function(defineComponent, withAuthTokemFromHash) {
    'use strict';
    return defineComponent(issuesExporter, withAuthTokemFromHash);

    function issuesExporter() {
      var issuesToExport = [];

      var csvLink = '';

      this.mountExportCsvLink = function(ev, data) {
        $('#export_csv').attr('disabled', true);
        var repositoriesUrls = this.getRepositoriesUrlsFromIssues(data.issues);
        issuesToExport = data.issues;
        this.getEventsFromProjects(repositoriesUrls);
      };

      this.clearLink = function() {
        csvLink = '';
      };

      this.linkToCsv = function(data) {
        var issuesCsv = this.issuesToCsv(data);
        if (csvLink === '') {
          issuesCsv.splice(0, 0, csvHeader());
        }

        csvLink += encodeURIComponent(issuesCsv.join('\n') + '\n');
        return 'data:text/csv;charset=utf8,' + csvLink;
      };

      this.validIssuesToExport = function(issues) {
        return _.filter(issues, function(issue) {
          return issue.projectName !== undefined;
        });
      };

      this.issuesToCsv = function(issues) {
        var issuesCsv = _.map(this.validIssuesToExport(issues), function(issue) {
          return ['\"' + issue.projectName + "\"",
            issue.number,
            "\"" + issue.title + "\"",
            issue.state,
            issue.kanbanState,
            "\"" + _.map(issue.labels, function(label) {
              return label.name;
            }) + "\"",
            issue.created_at,
            issue.dev_at,
            issue.closed_at,
            daysBetween(issue.created_at, issue.closed_at),
            daysBetween(issue.dev_at, issue.closed_at)
          ].join(';');
        });

        return issuesCsv;
      };

      function daysBetween(earlierDate, lateDate) {
        if ((earlierDate && lateDate) && (lateDate > earlierDate)) {
          var leadTime,
            millisecondsInDay = 86400000;

          leadTime = (new Date(lateDate) - new Date(earlierDate)) / millisecondsInDay;
          leadTime = parseInt(leadTime);

          return leadTime;
        } else {
          return "";
        }
      };

      function csvHeader() {
        return ["Source", "Github ID", "Title", "Status", "Kanban State", "Tags", "Create at", "Dev at", "Closed at", "Lead Time", "Cycle Time"].join(';');
      };

      this.getEventsFromProjects = function(projectsUrl) {
        var events = [];
        var self = this;

        function getEvents(url) {
          $.get(url, function(data, textStatus, request) {
            events = events.concat(data);

            try {
              var header = request.getResponseHeader('Link');
              var next = header.match(/<.*?>; rel="next"/)[0].match(/https.*[0-9]+/)[0];
              if (next) {
                getEvents(next);
              }
            } catch (err) {}
          });
        }

        $.each(projectsUrl, function(index, val) {
          getEvents(val + 'issues/events?per_page=100&access_token=' + this.getCurrentAuthToken());
        }.bind(self));

        $(document).one('ajaxStop', function() {
          self.createCsvUri(self.addDevDateForIssues(issuesToExport, events));
        });
      };

      this.groupEventsByIssuesId = function(events) {
        return _.groupBy(events, function(event) {
          return event.issue.id;
        });
      };

      this.excludeNonLabeledEvents = function(mappedEvents) {
        return _.object(_.map(mappedEvents, function(issueEvents, key) {
          return [key, _.filter(issueEvents, function(event) {
            return event.event == 'labeled';
          })]
        }));
      };

      this.getOnlyDevelopmentIssueEvents = function(labeledEvents) {
        return _.object(_.map(labeledEvents, function(issueEvents, key) {
          return [key, _.filter(issueEvents, function(event) {
            return event.label.name == '2 - Development';
          })]
        }));
      };

      this.getEarliestDevelopmentIssueEvents = function(developmentEvents) {
        return _.object(_.map(developmentEvents, function(events, key) {
          return [key, _.first(_.sortBy(events, function(e) {
            return e.created_at;
          }))]
        }));
      };

      this.mergeEventsWithIssues = function(issues, events) {
        return _.each(issues, function(issue) {
          if (events[issue.id]) {
            issue.dev_at = events[issue.id].created_at;
          }
        });
      };

      this.getRepositoriesUrlsFromIssues = function(issues) {
        return _.uniq(_.pluck(issues, 'repoUrl'));
      };

      this.addDevDateForIssues = function(issues, events) {
        var groupedEventsByIssueId = {},
          labeledEvents = {},
          developmentEvents = {},
          earlierstDevelopemntIssuesEvent = {},
          issuesWithDevDate = {};

        groupedEventsByIssueId = this.groupEventsByIssuesId(events);
        labeledEvents = this.excludeNonLabeledEvents(groupedEventsByIssueId);
        developmentEvents = this.getOnlyDevelopmentIssueEvents(labeledEvents);
        earlierstDevelopemntIssuesEvent = this.getEarliestDevelopmentIssueEvents(developmentEvents);
        issuesWithDevDate = this.mergeEventsWithIssues(issues, earlierstDevelopemntIssuesEvent);

        return issuesWithDevDate;
      };

      this.createCsvUri = function(issuesWithDevDate) {
        var uri = this.linkToCsv(issuesWithDevDate);

        var downloadLink = document.createElement("a");
        downloadLink.href = uri;
        downloadLink.download = "data.csv";

        document.body.appendChild(downloadLink);
        downloadLink.click();
        document.body.removeChild(downloadLink);
        $("#export_csv").attr("disabled", false);
        issuesToExport = [];
        this.trigger('data:issues:clearExportCsvLink');

      };

      this.after('initialize', function() {
        this.on('data:issues:mountExportCsvLink', this.mountExportCsvLink);
        this.on('data:issues:clearExportCsvLink', this.clearLink);
      });
    }
  }
);
<commit_msg>Add the qa_at methods to the issues exporter<commit_after>/*
 * Copyright 2014 Thoughtworks Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
define([
    'flight/lib/component',
    'component/mixins/with_auth_token_from_hash',
  ],
  function(defineComponent, withAuthTokemFromHash) {
    'use strict';
    return defineComponent(issuesExporter, withAuthTokemFromHash);

    function issuesExporter() {
      var issuesToExport = [];

      var csvLink = '';

      this.mountExportCsvLink = function(ev, data) {
        $('#export_csv').attr('disabled', true);
        var repositoriesUrls = this.getRepositoriesUrlsFromIssues(data.issues);
        issuesToExport = data.issues;
        this.getEventsFromProjects(repositoriesUrls);
      };

      this.clearLink = function() {
        csvLink = '';
      };

      this.linkToCsv = function(data) {
        var issuesCsv = this.issuesToCsv(data);
        if (csvLink === '') {
          issuesCsv.splice(0, 0, csvHeader());
        }

        csvLink += encodeURIComponent(issuesCsv.join('\n') + '\n');
        return 'data:text/csv;charset=utf8,' + csvLink;
      };

      this.validIssuesToExport = function(issues) {
        return _.filter(issues, function(issue) {
          return issue.projectName !== undefined;
        });
      };

      this.issuesToCsv = function(issues) {
        var issuesCsv = _.map(this.validIssuesToExport(issues), function(issue) {
          return ['\"' + issue.projectName + "\"",
            issue.number,
            "\"" + issue.title + "\"",
            issue.state,
            issue.kanbanState,
            "\"" + _.map(issue.labels, function(label) {
              return label.name;
            }) + "\"",
            issue.created_at,
            issue.dev_at,
            issue.qa_at,
            issue.closed_at,
            daysBetween(issue.created_at, issue.closed_at),
            daysBetween(issue.dev_at, issue.closed_at)
          ].join(';');
        });

        return issuesCsv;
      };

      function daysBetween(earlierDate, lateDate) {
        if ((earlierDate && lateDate) && (lateDate > earlierDate)) {
          var leadTime,
            millisecondsInDay = 86400000;

          leadTime = (new Date(lateDate) - new Date(earlierDate)) / millisecondsInDay;
          leadTime = parseInt(leadTime);

          return leadTime;
        } else {
          return "";
        }
      };

      function csvHeader() {
        return ["Source", "Github ID", "Title", "Status", "Kanban State", "Tags", "Create at", "Dev at", "QA at", "Closed at", "Lead Time", "Cycle Time"].join(';');
      };

      this.getEventsFromProjects = function(projectsUrl) {
        var events = [];
        var self = this;

        function getEvents(url) {
          $.get(url, function(data, textStatus, request) {
            events = events.concat(data);

            try {
              var header = request.getResponseHeader('Link');
              var next = header.match(/<.*?>; rel="next"/)[0].match(/https.*[0-9]+/)[0];
              if (next) {
                getEvents(next);
              }
            } catch (err) {}
          });
        }

        $.each(projectsUrl, function(index, val) {
          getEvents(val + 'issues/events?per_page=100&access_token=' + this.getCurrentAuthToken());
        }.bind(self));

        $(document).one('ajaxStop', function() {
          self.createCsvUri(self.addDevAndQaDateForIssues(issuesToExport, events));
        });
      };

      this.groupEventsByIssuesId = function(events) {
        return _.groupBy(events, function(event) {
          return event.issue.id;
        });
      };

      this.excludeNonLabeledEvents = function(mappedEvents) {
        return _.object(_.map(mappedEvents, function(issueEvents, key) {
          return [key, _.filter(issueEvents, function(event) {
            return event.event == 'labeled';
          })]
        }));
      };

      this.getOnlyDevelopmentIssueEvents = function(labeledEvents) {
        return _.object(_.map(labeledEvents, function(issueEvents, key) {
          return [key, _.filter(issueEvents, function(event) {
            return event.label.name == '2 - Development';
          })]
        }));
      };

      this.getEarliestDevelopmentIssueEvents = function(developmentEvents) {
        return _.object(_.map(developmentEvents, function(events, key) {
          return [key, _.first(_.sortBy(events, function(e) {
            return e.created_at;
          }))]
        }));
      };

      this.getOnlyQaIssueEvents = function(labeledEvents) {
        return _.object(_.map(labeledEvents, function(issueEvents, key) {
          return [key, _.filter(issueEvents, function(event) {
            return event.label.name == '3 - QA';
          })]
        }));
      };

      this.getEarliestQaIssueEvents = function(qaEvents) {
        return _.object(_.map(qaEvents, function(events, key) {
          return [key, _.first(_.sortBy(events, function(e) {
            return e.created_at;
          }))]
        }));
      };

      this.mergeDevEventsWithIssues = function(issues, events) {
        return _.each(issues, function(issue) {
          if (events[issue.id]) {
            issue.dev_at = events[issue.id].created_at;
          }
        });
      };

      this.mergeQaEventsWithIssues = function(issues, events) {
        return _.each(issues, function(issue) {
          if (events[issue.id]) {
            issue.qa_at = events[issue.id].created_at;
          }
        });
      };

      this.getRepositoriesUrlsFromIssues = function(issues) {
        return _.uniq(_.pluck(issues, 'repoUrl'));
      };

      this.addDevAndQaDateForIssues = function(issues, events) {
        var groupedEventsByIssueId = {},
          labeledEvents = {},
          developmentEvents = {},
          earlierstDevelopemntIssuesEvent = {},
          qaEvents = {},
          earlierstQaIssuesEvent = {},
          issuesWithDevDate = {},
          issuesWithDevAndQaDate = {};

        groupedEventsByIssueId = this.groupEventsByIssuesId(events);
        labeledEvents = this.excludeNonLabeledEvents(groupedEventsByIssueId);
        developmentEvents = this.getOnlyDevelopmentIssueEvents(labeledEvents);
        earlierstDevelopemntIssuesEvent = this.getEarliestDevelopmentIssueEvents(developmentEvents);
        qaEvents = this.getOnlyQaIssueEvents(labeledEvents);
        earlierstQaIssuesEvent = this.getEarliestQaIssueEvents(developmentEvents);
        issuesWithDevDate = this.mergeDevEventsWithIssues(issues, earlierstDevelopemntIssuesEvent);
        issuesWithDevAndQaDate = this.mergeQaEventsWithIssues(issues, earlierstQaIssuesEvent);

        return issuesWithDevAndQaDate;
      };

      this.createCsvUri = function(issuesWithDevDate) {
        var uri = this.linkToCsv(issuesWithDevDate);

        var downloadLink = document.createElement("a");
        downloadLink.href = uri;
        downloadLink.download = "data.csv";

        document.body.appendChild(downloadLink);
        downloadLink.click();
        document.body.removeChild(downloadLink);
        $("#export_csv").attr("disabled", false);
        issuesToExport = [];
        this.trigger('data:issues:clearExportCsvLink');

      };

      this.after('initialize', function() {
        this.on('data:issues:mountExportCsvLink', this.mountExportCsvLink);
        this.on('data:issues:clearExportCsvLink', this.clearLink);
      });
    }
  }
);
<|endoftext|>


<commit_before>'use strict';

/**
 * PropertyCollectionCtrl
 * Controller which holds all the properties of a subject.
 */

angular.module('GSB.controllers.propertyCollection', ['GSB.config', 'GSB.services.availableClasses'])
//Inject $scope, $http, $log and globalConfig (see @js/config.js, @js/services/availableClasses.js) into controller
  .controller('PropertyCollectionCtrl', ['$scope', '$http', '$log', 'globalConfig', 'AvailableClassesService', function($scope, $http, $log, globalConfig, AvailableClassesService) {

    //Named a few variables, for shorter access
    var $parentSubject = $scope.subjectInst,
      $selectedProperties = $parentSubject.selectedProperties;
    $parentSubject.availableProperties = {};
    $scope.propertyOperators = globalConfig.propertyOperators;

    /**
     * Adds a property selected from the availableProperties of a
     * subjectInst to the selectedProperties of the same subjectInst
     */
    $scope.addProperty = function(){
      $selectedProperties.push(angular.copy($scope.propertySelected));
      $scope.propertySelected = '';
    };

    /**
     * Removes a given propertyInst from the selectedProperties of the subjectInst
     * @param propertyInst
     */
    $scope.removeProperty = function(propertyInst) {
      $selectedProperties.splice($selectedProperties.indexOf(propertyInst), 1);
    };

    /** FOLGENDES MUSS AUS DIESEM CONTROLLER RAUS!
     * TODO-SIGGI: Move the stuff below to the availableClasses/endPoint - Service.
     * **/

    $log.info('Lade die Properties von ' + $parentSubject.uri);

    //Retrieve Properties from Server and add them to availableProperties
    $http.get(globalConfig.baseURL + $parentSubject.uri).success(function (data){
      $log.info(' Properties loaded from: ' + $parentSubject.uri, data);
      $parentSubject.availableProperties = {};
      var returnedProperties = data.results.bindings;
      for (var key in returnedProperties){
        if(returnedProperties.hasOwnProperty(key)){
          $scope.addToAvailableProperties(returnedProperties[key]);
        }
      }
    }).error(function(){
      $log.error('Error loading properties from: ' + $parentSubject.uri)
    });

    /**
     * Returns whether an property is an objectProperty
     * @param propertyRange
     * @returns {boolean}
     */
    $scope.isObjectProperty = function (propertyRange) {
      var dataTypeURIs = globalConfig['dataTypeURIs'];
      for(var key in dataTypeURIs){
        if(dataTypeURIs.hasOwnProperty(key) && propertyRange.startsWith(dataTypeURIs[key])){
          return false;
        }
      }
      return true;
    };

    /**
     * Adds a given property to the availableProperties of a subjectInst
     * @param property
     * @namespace property.propertyURI
     */
    $scope.addToAvailableProperties = function (property) {
      var propertyURI = property.propertyURI.value,
        propertyRange = property.propertyRange.value,
        isObjectProperty = ($scope.isObjectProperty(propertyRange));
      if($parentSubject.availableProperties.hasOwnProperty(propertyURI)){
        $parentSubject.availableProperties[propertyURI].propertyRange.push(propertyRange);
      }else {
        $parentSubject.availableProperties[propertyURI] = {
          alias: property.propertyAlias.value,
          uri: propertyURI,
          type: isObjectProperty ? 'OBJECT_PROPERTY' : 'DATATYPE_PROPERTY',
          isObjectProperty: isObjectProperty,
          propertyRange: [propertyRange],
          view: true,
          operator: "MUST", //Vorprojekt okay
          link : {direction: "TO", linkPartner: null}, //Vorprojekt okay
          arithmetic : {} , //Vorprojekt leave empty
          compare : {} //Vorprojekt leave empty
        };
      }
    };

  }]);<commit_msg>Changed variable names in propertyCollection.<commit_after>'use strict';

/**
 * PropertyCollectionCtrl
 * Controller which holds all the properties of a subject.
 */

angular.module('GSB.controllers.propertyCollection', ['GSB.config', 'GSB.services.availableClasses'])
//Inject $scope, $http, $log and globalConfig (see @js/config.js, @js/services/availableClasses.js) into controller
  .controller('PropertyCollectionCtrl', ['$scope', '$http', '$log', 'globalConfig', 'AvailableClassesService', function($scope, $http, $log, globalConfig, AvailableClassesService) {

    var selectedProperties = $scope.subjectInst.selectedProperties;
    $scope.subjectInst.availableProperties = AvailableClassesService.getProperties($scope.subjectInst.uri);
    $scope.propertyOperators = globalConfig.propertyOperators;

    /**
     * Adds a property selected from the availableProperties of a
     * subjectInst to the selectedProperties of the same subjectInst
     */
    $scope.addProperty = function(){
      selectedProperties.push(angular.copy($scope.propertySelected));
      $scope.propertySelected = '';
    };

    /**
     * Removes a given propertyInst from the selectedProperties of the subjectInst
     * @param propertyInst
     */
    $scope.removeProperty = function(propertyInst) {
      selectedProperties.splice(selectedProperties.indexOf(propertyInst), 1);
    };

    /** FOLGENDES MUSS AUS DIESEM CONTROLLER RAUS!
     * TODO-SIGGI: Move the stuff below to the availableClasses/endPoint - Service.
     * **/

    $log.info('Lade die Properties von ' + $parentSubject.uri);

    //Retrieve Properties from Server and add them to availableProperties
    $http.get(globalConfig.baseURL + $parentSubject.uri).success(function (data){
      $log.info(' Properties loaded from: ' + $parentSubject.uri, data);
      $parentSubject.availableProperties = {};
      var returnedProperties = data.results.bindings;
      for (var key in returnedProperties){
        if(returnedProperties.hasOwnProperty(key)){
          $scope.addToAvailableProperties(returnedProperties[key]);
        }
      }
    }).error(function(){
      $log.error('Error loading properties from: ' + $parentSubject.uri)
    });

    /**
     * Returns whether an property is an objectProperty
     * @param propertyRange
     * @returns {boolean}
     */
    $scope.isObjectProperty = function (propertyRange) {
      var dataTypeURIs = globalConfig['dataTypeURIs'];
      for(var key in dataTypeURIs){
        if(dataTypeURIs.hasOwnProperty(key) && propertyRange.startsWith(dataTypeURIs[key])){
          return false;
        }
      }
      return true;
    };

    /**
     * Adds a given property to the availableProperties of a subjectInst
     * @param property
     * @namespace property.propertyURI
     */
    $scope.addToAvailableProperties = function (property) {
      var propertyURI = property.propertyURI.value,
        propertyRange = property.propertyRange.value,
        isObjectProperty = ($scope.isObjectProperty(propertyRange));
      if($parentSubject.availableProperties.hasOwnProperty(propertyURI)){
        $parentSubject.availableProperties[propertyURI].propertyRange.push(propertyRange);
      }else {
        $parentSubject.availableProperties[propertyURI] = {
          alias: property.propertyAlias.value,
          uri: propertyURI,
          type: isObjectProperty ? 'OBJECT_PROPERTY' : 'DATATYPE_PROPERTY',
          isObjectProperty: isObjectProperty,
          propertyRange: [propertyRange],
          view: true,
          operator: "MUST", //Vorprojekt okay
          link : {direction: "TO", linkPartner: null}, //Vorprojekt okay
          arithmetic : {} , //Vorprojekt leave empty
          compare : {} //Vorprojekt leave empty
        };
      }
    };

  }]);<|endoftext|>


<commit_before>/**
 * Copyright 2015 Google Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

(function(global) {
  var DEFAULT_PROFILE_IMAGE_URL = 'images/touch/homescreen96.png';

  function profileImageRequest(request) {
    return global.toolbox.cacheFirst(request).catch(function() {
      return global.toolbox.cacheOnly(new Request(DEFAULT_PROFILE_IMAGE_URL));
    });
  }

  global.toolbox.precache([DEFAULT_PROFILE_IMAGE_URL]);
  global.toolbox.router.get('/(.+)/images/speakers/(.*)', profileImageRequest, {origin: /.*\.googleapis\.com/});
})(self);
<commit_msg>Use networkFirst for speaker profile images (#704)<commit_after>/**
 * Copyright 2015 Google Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

(function(global) {
  var DEFAULT_PROFILE_IMAGE_URL = 'images/touch/homescreen96.png';

  function profileImageRequest(request) {
    return global.toolbox.networkFirst(request).catch(function() {
      return global.toolbox.cacheOnly(new Request(DEFAULT_PROFILE_IMAGE_URL));
    });
  }

  global.toolbox.precache([DEFAULT_PROFILE_IMAGE_URL]);
  global.toolbox.router.get('/(.+)/images/speakers/(.*)', profileImageRequest, {origin: /.*\.googleapis\.com/});
})(self);
<|endoftext|>


<commit_before>import Color from './color';
import Rgb   from './rgb';

const NAME = Symbol.for();
const KEYS = Object.freeze({
  Y:  Symbol.for('y'),
  DB: Symbol.for('db'),
  DR: Symbol.for('dr')
});

export default class YDbDr extends Color {
  constructor(y, db, dr) {
    super(NAME, [[KEYS.Y, y], [KEYS.DB, db], [KEYS.DR, dr]]);
  }

  rgb() {
    let [y, db, dr] = this.values();

    let r = y + 0.000092303716148 * db - 0.525912630661865 * dr;
    let g = y - 0.129132898890509 * db + 0.267899328207599 * dr;
    let b = y + 0.664679059978955 * db - 0.000079202543533 * dr;
    [r, g, b] = [r, g, b].map(value => Math.round(value * 0xFF));
    return new Rgb(r, g, b);
  }

  ydbdr() {
    return this;
  }
}
<commit_msg>Fixed lint errors<commit_after>import Color from './color';
import Rgb   from './rgb';

const NAME = Symbol.for();
const KEYS = Object.freeze({
  Y:  Symbol.for('y'),
  DB: Symbol.for('db'),
  DR: Symbol.for('dr')
});

export default class YDbDr extends Color {
  constructor(y, db, dr) {
    super(NAME, [[KEYS.Y, y], [KEYS.DB, db], [KEYS.DR, dr]]);
  }

  rgb() {
    const [y, db, dr] = this.values();

    let r = y + 0.000092303716148 * db - 0.525912630661865 * dr;
    let g = y - 0.129132898890509 * db + 0.267899328207599 * dr;
    let b = y + 0.664679059978955 * db - 0.000079202543533 * dr;
    [r, g, b] = [r, g, b].map((value) => { Math.round(value * 0xFF) });
    return new Rgb(r, g, b);
  }

  ydbdr() {
    return this;
  }
}
<|endoftext|>


<commit_before>
(function () {
    angular
        .module('andyBeeApp')
        .factory('GeocacheService', GeocacheService);

    GeocacheService.$inject = ['$rootScope', '$resource', 'PreferenceService', 'LoggingService'];
    function GeocacheService ($rootScope, $resource, PreferenceService, LoggingService) {
        var rest_dblist = $resource('/andyBee/api/v1.0/db/', null, {
            post: {
                method: 'POST'
            }
        });
        var rest_geocache = $resource('/andyBee/api/v1.0/db/:db/geocaches/:geocache_id');
        var serv = {
            // which of the tabs (list, map, detail, console) is active
            detail: {},
            selected_tab: 0,
            show_details: show_details,

            // stuff related to the list of DBs
            db_list: [],
            get_dblist: get_dblist,
            db_name: '',

            // stuff related to geocaches within a db
            geocache_list: [],
            get_geocache_list: get_geocache_list,

        };

        return serv;

        function get_dblist (success_cb) {
            rest_dblist.get(dblist_response, LoggingService.log_RESTful_error);

            function dblist_response (result) {
                serv.db_list = result.dbs;
                success_cb();
            }
        }

        function get_geocache_list (db_name) {
            if (inArray(db_name, serv.db_list)) {
                rest_geocache.get({db: db_name}, geocache_list_response, LoggingService.log_RESTful_error);
            }
            else {
                // new DB to allocate.
                rest_dblist.post({db: db_name}, db_allocated, LoggingService.log_RESTful_error);
            }

            function db_allocated (result) {
                serv.db_name = result.db_name;
                PreferenceService.update_used_db(result.db_name);
                serv.nbr_caches = 0;
                serv.geocache_list = [];
                $rootScope.$broadcast('geocaches_updated');
            }

            function geocache_list_response (result) {
                serv.db_name = result.db_name;
                PreferenceService.update_used_db(result.db_name);
                serv.nbr_caches = result.nbr_caches;
                serv.geocache_list = result.geocaches;
                $rootScope.$broadcast('geocaches_updated');
            }
        }

        function show_details (id) {
            serv.selected_tab = 2; // switch to the details tab
            rest_geocache.get({db: serv.db_name, geocache_id: id}, geocache_response, LoggingService.log_RESTful_error);

            function geocache_response (result) {
                serv.detail = result.geocache;
                $rootScope.$broadcast('geocache_details_updated');
            }
        }

        function inArray(needle, haystack) {
            var length = haystack.length;
            for (var i = 0; i < length; i++) {
                if (haystack[i] == needle)
                    return true;
            }
            return false;
        }
    }

})();
<commit_msg>Cosmetical change<commit_after>
(function () {
    angular
        .module('andyBeeApp')
        .factory('GeocacheService', GeocacheService);

    GeocacheService.$inject = ['$rootScope', '$resource', 'PreferenceService', 'LoggingService'];
    function GeocacheService ($rootScope, $resource, PreferenceService, LoggingService) {
        var rest_dblist = $resource('/andyBee/api/v1.0/db/', null, {
            post: {
                method: 'POST'
            }
        });
        var rest_geocache = $resource('/andyBee/api/v1.0/db/:db/geocaches/:geocache_id');
        var serv = {
            // which of the tabs (list, map, detail, console) is active
            selected_tab: 0,
            detail: {},
            show_details: show_details,

            // stuff related to the list of DBs
            db_list: [],
            get_dblist: get_dblist,
            db_name: '',

            // stuff related to geocaches within a db
            geocache_list: [],
            get_geocache_list: get_geocache_list,

        };

        return serv;

        function get_dblist (success_cb) {
            rest_dblist.get(dblist_response, LoggingService.log_RESTful_error);

            function dblist_response (result) {
                serv.db_list = result.dbs;
                success_cb();
            }
        }

        function get_geocache_list (db_name) {
            if (inArray(db_name, serv.db_list)) {
                rest_geocache.get({db: db_name}, geocache_list_response, LoggingService.log_RESTful_error);
            }
            else {
                // new DB to allocate.
                rest_dblist.post({db: db_name}, db_allocated, LoggingService.log_RESTful_error);
            }

            function db_allocated (result) {
                serv.db_name = result.db_name;
                PreferenceService.update_used_db(result.db_name);
                serv.nbr_caches = 0;
                serv.geocache_list = [];
                $rootScope.$broadcast('geocaches_updated');
            }

            function geocache_list_response (result) {
                serv.db_name = result.db_name;
                PreferenceService.update_used_db(result.db_name);
                serv.nbr_caches = result.nbr_caches;
                serv.geocache_list = result.geocaches;
                $rootScope.$broadcast('geocaches_updated');
            }
        }

        function show_details (id) {
            serv.selected_tab = 2; // switch to the details tab
            rest_geocache.get({db: serv.db_name, geocache_id: id}, geocache_response, LoggingService.log_RESTful_error);

            function geocache_response (result) {
                serv.detail = result.geocache;
                $rootScope.$broadcast('geocache_details_updated');
            }
        }

        function inArray(needle, haystack) {
            var length = haystack.length;
            for (var i = 0; i < length; i++) {
                if (haystack[i] == needle)
                    return true;
            }
            return false;
        }
    }

})();
<|endoftext|>


<commit_before>var specialProperties = require('ui/builder/special-properties'),
    gestures = require('ui/gestures'),
    util = require('utils/utils'),
    helpers = require('./helper'),
    app = require('application');

specialProperties.registerSpecialProperty('externalAddress', (instance, value) => {
    if (value.substring(0, 4) === 'geo:' && app.ios) {
        value = 'http://maps.apple.com/?ll=' + value.substring(4, value.length);
    }

    instance.on(gestures.GestureTypes.tap, () => {
        util.openUrl(value);
    });
});

specialProperties.registerSpecialProperty('linkToView', (instance, value) => {
    instance.on(gestures.GestureTypes.tap, () => {
        helpers.navigate({
            moduleName: value
        });
    });
});
<commit_msg>clear natigation-property code as breaking changes in tns core modules 3.0.0 removed<commit_after><|endoftext|>


<commit_before>// @flow

import invariant from 'invariant';
import * as React from 'react';
import { useDispatch } from 'react-redux';
import { createSelector } from 'reselect';

import { nonThreadCalendarFiltersSelector } from 'lib/selectors/calendar-filter-selectors';
import { currentCalendarQuery } from 'lib/selectors/nav-selectors';
import { createPendingSidebar } from 'lib/shared/thread-utils';
import type { CalendarQuery } from 'lib/types/entry-types';
import type { CalendarFilter } from 'lib/types/filter-types';
import type {
  ComposableMessageInfo,
  RobotextMessageInfo,
} from 'lib/types/message-types';
import type { ThreadInfo } from 'lib/types/thread-types';

import { getDefaultTextMessageRules } from '../markdown/rules.react';
import type { AppState } from '../redux/redux-setup';
import { useSelector } from '../redux/redux-utils';
import { updateNavInfoActionType } from '../types/nav-types';

const dateExtractionRegex = /^([0-9]{4})-([0-9]{2})-[0-9]{2}$/;

function yearExtractor(startDate: string, endDate: string): ?number {
  const startDateResults = dateExtractionRegex.exec(startDate);
  const endDateResults = dateExtractionRegex.exec(endDate);
  if (
    !startDateResults ||
    !startDateResults[1] ||
    !endDateResults ||
    !endDateResults[1] ||
    startDateResults[1] !== endDateResults[1]
  ) {
    return null;
  }
  return parseInt(startDateResults[1], 10);
}

function yearAssertingExtractor(startDate: string, endDate: string): number {
  const result = yearExtractor(startDate, endDate);
  invariant(
    result !== null && result !== undefined,
    `${startDate} and ${endDate} aren't in the same year`,
  );
  return result;
}

const yearAssertingSelector: (state: AppState) => number = createSelector(
  (state: AppState) => state.navInfo.startDate,
  (state: AppState) => state.navInfo.endDate,
  yearAssertingExtractor,
);

// 1-indexed
function monthExtractor(startDate: string, endDate: string): ?number {
  const startDateResults = dateExtractionRegex.exec(startDate);
  const endDateResults = dateExtractionRegex.exec(endDate);
  if (
    !startDateResults ||
    !startDateResults[1] ||
    !startDateResults[2] ||
    !endDateResults ||
    !endDateResults[1] ||
    !endDateResults[2] ||
    startDateResults[1] !== endDateResults[1] ||
    startDateResults[2] !== endDateResults[2]
  ) {
    return null;
  }
  return parseInt(startDateResults[2], 10);
}

// 1-indexed
function monthAssertingExtractor(startDate: string, endDate: string): number {
  const result = monthExtractor(startDate, endDate);
  invariant(
    result !== null && result !== undefined,
    `${startDate} and ${endDate} aren't in the same month`,
  );
  return result;
}

// 1-indexed
const monthAssertingSelector: (state: AppState) => number = createSelector(
  (state: AppState) => state.navInfo.startDate,
  (state: AppState) => state.navInfo.endDate,
  monthAssertingExtractor,
);

function activeThreadSelector(state: AppState): ?string {
  return state.navInfo.tab === 'chat' ? state.navInfo.activeChatThreadID : null;
}

const webCalendarQuery: (
  state: AppState,
) => () => CalendarQuery = createSelector(
  currentCalendarQuery,
  (state: AppState) => state.navInfo.tab === 'calendar',
  (
    calendarQuery: (calendarActive: boolean) => CalendarQuery,
    calendarActive: boolean,
  ) => () => calendarQuery(calendarActive),
);

const nonThreadCalendarQuery: (
  state: AppState,
) => () => CalendarQuery = createSelector(
  webCalendarQuery,
  nonThreadCalendarFiltersSelector,
  (
    calendarQuery: () => CalendarQuery,
    filters: $ReadOnlyArray<CalendarFilter>,
  ) => {
    return (): CalendarQuery => {
      const query = calendarQuery();
      return {
        startDate: query.startDate,
        endDate: query.endDate,
        filters,
      };
    };
  },
);

function useOnClickThread(threadID: string) {
  const dispatch = useDispatch();
  return React.useCallback(
    (event: SyntheticEvent<HTMLAnchorElement>) => {
      event.preventDefault();
      dispatch({
        type: updateNavInfoActionType,
        payload: {
          activeChatThreadID: threadID,
        },
      });
    },
    [dispatch, threadID],
  );
}

function useThreadIsActive(threadID: string) {
  return useSelector((state) => threadID === state.navInfo.activeChatThreadID);
}

function useOnClickPendingSidebar(
  messageInfo: ComposableMessageInfo | RobotextMessageInfo,
  threadInfo: ThreadInfo,
) {
  const dispatch = useDispatch();
  const viewerID = useSelector((state) => state.currentUserInfo?.id);
  return React.useCallback(
    (event: SyntheticEvent<HTMLElement>) => {
      event.preventDefault();
      if (!viewerID) {
        return;
      }
      const pendingSidebarInfo = createPendingSidebar(
        messageInfo,
        threadInfo,
        viewerID,
        getDefaultTextMessageRules().simpleMarkdownRules,
      );
      dispatch({
        type: updateNavInfoActionType,
        payload: {
          activeChatThreadID: pendingSidebarInfo.id,
          pendingThread: pendingSidebarInfo,
          sourceMessageID: messageInfo.id,
        },
      });
    },
    [viewerID, messageInfo, threadInfo, dispatch],
  );
}

export {
  yearExtractor,
  yearAssertingSelector,
  monthExtractor,
  monthAssertingSelector,
  activeThreadSelector,
  webCalendarQuery,
  nonThreadCalendarQuery,
  useOnClickThread,
  useThreadIsActive,
  useOnClickPendingSidebar,
};
<commit_msg>[web] Allow nullable threadID in useOnClickThread<commit_after>// @flow

import invariant from 'invariant';
import * as React from 'react';
import { useDispatch } from 'react-redux';
import { createSelector } from 'reselect';

import { nonThreadCalendarFiltersSelector } from 'lib/selectors/calendar-filter-selectors';
import { currentCalendarQuery } from 'lib/selectors/nav-selectors';
import { createPendingSidebar } from 'lib/shared/thread-utils';
import type { CalendarQuery } from 'lib/types/entry-types';
import type { CalendarFilter } from 'lib/types/filter-types';
import type {
  ComposableMessageInfo,
  RobotextMessageInfo,
} from 'lib/types/message-types';
import type { ThreadInfo } from 'lib/types/thread-types';

import { getDefaultTextMessageRules } from '../markdown/rules.react';
import type { AppState } from '../redux/redux-setup';
import { useSelector } from '../redux/redux-utils';
import { updateNavInfoActionType } from '../types/nav-types';

const dateExtractionRegex = /^([0-9]{4})-([0-9]{2})-[0-9]{2}$/;

function yearExtractor(startDate: string, endDate: string): ?number {
  const startDateResults = dateExtractionRegex.exec(startDate);
  const endDateResults = dateExtractionRegex.exec(endDate);
  if (
    !startDateResults ||
    !startDateResults[1] ||
    !endDateResults ||
    !endDateResults[1] ||
    startDateResults[1] !== endDateResults[1]
  ) {
    return null;
  }
  return parseInt(startDateResults[1], 10);
}

function yearAssertingExtractor(startDate: string, endDate: string): number {
  const result = yearExtractor(startDate, endDate);
  invariant(
    result !== null && result !== undefined,
    `${startDate} and ${endDate} aren't in the same year`,
  );
  return result;
}

const yearAssertingSelector: (state: AppState) => number = createSelector(
  (state: AppState) => state.navInfo.startDate,
  (state: AppState) => state.navInfo.endDate,
  yearAssertingExtractor,
);

// 1-indexed
function monthExtractor(startDate: string, endDate: string): ?number {
  const startDateResults = dateExtractionRegex.exec(startDate);
  const endDateResults = dateExtractionRegex.exec(endDate);
  if (
    !startDateResults ||
    !startDateResults[1] ||
    !startDateResults[2] ||
    !endDateResults ||
    !endDateResults[1] ||
    !endDateResults[2] ||
    startDateResults[1] !== endDateResults[1] ||
    startDateResults[2] !== endDateResults[2]
  ) {
    return null;
  }
  return parseInt(startDateResults[2], 10);
}

// 1-indexed
function monthAssertingExtractor(startDate: string, endDate: string): number {
  const result = monthExtractor(startDate, endDate);
  invariant(
    result !== null && result !== undefined,
    `${startDate} and ${endDate} aren't in the same month`,
  );
  return result;
}

// 1-indexed
const monthAssertingSelector: (state: AppState) => number = createSelector(
  (state: AppState) => state.navInfo.startDate,
  (state: AppState) => state.navInfo.endDate,
  monthAssertingExtractor,
);

function activeThreadSelector(state: AppState): ?string {
  return state.navInfo.tab === 'chat' ? state.navInfo.activeChatThreadID : null;
}

const webCalendarQuery: (
  state: AppState,
) => () => CalendarQuery = createSelector(
  currentCalendarQuery,
  (state: AppState) => state.navInfo.tab === 'calendar',
  (
    calendarQuery: (calendarActive: boolean) => CalendarQuery,
    calendarActive: boolean,
  ) => () => calendarQuery(calendarActive),
);

const nonThreadCalendarQuery: (
  state: AppState,
) => () => CalendarQuery = createSelector(
  webCalendarQuery,
  nonThreadCalendarFiltersSelector,
  (
    calendarQuery: () => CalendarQuery,
    filters: $ReadOnlyArray<CalendarFilter>,
  ) => {
    return (): CalendarQuery => {
      const query = calendarQuery();
      return {
        startDate: query.startDate,
        endDate: query.endDate,
        filters,
      };
    };
  },
);

function useOnClickThread(threadID: ?string) {
  const dispatch = useDispatch();
  return React.useCallback(
    (event: SyntheticEvent<HTMLElement>) => {
      invariant(
        threadID,
        'useOnClickThread should be called with threadID set',
      );
      event.preventDefault();
      dispatch({
        type: updateNavInfoActionType,
        payload: {
          activeChatThreadID: threadID,
        },
      });
    },
    [dispatch, threadID],
  );
}

function useThreadIsActive(threadID: string) {
  return useSelector((state) => threadID === state.navInfo.activeChatThreadID);
}

function useOnClickPendingSidebar(
  messageInfo: ComposableMessageInfo | RobotextMessageInfo,
  threadInfo: ThreadInfo,
) {
  const dispatch = useDispatch();
  const viewerID = useSelector((state) => state.currentUserInfo?.id);
  return React.useCallback(
    (event: SyntheticEvent<HTMLElement>) => {
      event.preventDefault();
      if (!viewerID) {
        return;
      }
      const pendingSidebarInfo = createPendingSidebar(
        messageInfo,
        threadInfo,
        viewerID,
        getDefaultTextMessageRules().simpleMarkdownRules,
      );
      dispatch({
        type: updateNavInfoActionType,
        payload: {
          activeChatThreadID: pendingSidebarInfo.id,
          pendingThread: pendingSidebarInfo,
          sourceMessageID: messageInfo.id,
        },
      });
    },
    [viewerID, messageInfo, threadInfo, dispatch],
  );
}

export {
  yearExtractor,
  yearAssertingSelector,
  monthExtractor,
  monthAssertingSelector,
  activeThreadSelector,
  webCalendarQuery,
  nonThreadCalendarQuery,
  useOnClickThread,
  useThreadIsActive,
  useOnClickPendingSidebar,
};
<|endoftext|>


<commit_before>/**
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 **/

importScripts('/bower_components/sw-toolbox/sw-toolbox.js');

const config = {
  offlinePage: '/youre_offline/'
}

const IGNORED_URLS = ['shopping_cart']

config.filesToCache = [
    '/',
    '/components/amp-img/',
    '/components/amp-install-serviceworker/',
    config.offlinePage,
    '/img/offline.png',
    '/img/logo.svg',
    '/favicons/favicon.ico',
    '/favicons/favicon-230x230.png',
    '/favicons/favicon-96x96.png',
    '/favicons/android-chrome-36x36.png',
    '/favicons/android-chrome-72x72.png',
    '/img/ic_experiment_black_2x_web_18dp.png',
    '/img/ic_experiment_black_1x_web_18dp.png',
    '/img/ic_experiment_black_2x_web_24dp.png',
    '/img/ic_experiment_black_1x_web_24dp.png',
    '/img/ic_experiment_black_2x_web_36dp.png',
    '/img/ic_experiment_black_1x_web_36dp.png',
    '/img/ic_link_black_1x_web_18dp.png',
    '/img/ic_link_black_2x_web_18dp.png',
    '/img/ic_menu_white_1x_web_24dp.png',
    '/img/ic_menu_white_2x_web_24dp.png',
    '/img/ic_indeterminate_check_box_black_24dp_1x.png',
    '/img/ic_indeterminate_check_box_black_24dp_2x.png',
    '/img/ic_add_box_black_24dp_1x.png',
    '/img/ic_add_box_black_24dp_2x.png',
    '/img/ic_chevron_left_black_24dp_1x.png',
    '/img/ic_chevron_left_black_24dp_2x.png',
    '/img/ic_play_arrow_white_1x_web_24dp.png',
    '/img/ic_play_arrow_white_2x_web_24dp.png',
    '/img/ic_mode_edit_white_24dp_1x.png',
    '/img/ic_mode_edit_white_24dp_2x.png',
    '/img/GitHub-Mark-Light-32px.png',
    '/img/GitHub-Mark-Light-64px.png',
    '/playground/img/playground-logo.svg',
    '/playground/'
];

/**
 * Generates a placeholder SVG image of the given size.
 */
function offlineImage(name, width, height) {
  return `<?xml version="1.0"?>
<svg width="${width}" height="${height}" viewBox="0 0 ${width} ${height}" xmlns="http://www.w3.org/2000/svg" version="1.1">
  <g fill="none" fill-rule="evenodd"><path fill="#F8BBD0" d="M0 0h${width}v${height}H0z"/></g>
  <text text-anchor="middle" x="${Math.floor(width / 2)}" y="${Math.floor(height / 2)}">image offline (${name})</text>
<style><![CDATA[
text{
  font: 48px Roboto,Verdana, Helvetica, Arial, sans-serif;
}
]]></style>
</svg>`;
}
/**
 * Returns true if the Accept header contains the given content type string.
 */
function requestAccepts(request, contentType) {
  return request.headers.get('Accept').indexOf(contentType) != -1;
}

/**
 * ampbyexample.com fetch handler:
 *
 * - one-behind caching
 * - shows offline page
 * - generates placeholder image for unavailable images
 */
function ampByExampleHandler(request, values) {
  // for samples show offline page if offline and samples are not cached
  if (requestAccepts(request, 'text/html')) {
    // never use cached version for AMP CORS requests (e.g. amp-live-list) or pages that shouldn't be cached
    if (request.url.indexOf("__amp_source_origin") != -1 || shouldNotCache(request)) {
      return toolbox.networkOnly(request, values);
    }
    // cache or network - whatever is fastest
    return toolbox.fastest(request, values).catch(function() {
      return toolbox.cacheOnly(new Request(config.offlinePage), values)
        .then(function(response) {
          return response || new Response('You\'re offline. Sorry.', {
            status: 500,
            statusText: 'Offline Page Missing'
          });
        });
    });
  }
  // always try to load images from the cache first
  // fallback to placeholder SVG image if offline and image not available
  if (requestAccepts(request, 'image/')) {
    return toolbox.cacheFirst(request, values).catch(function() {
      const url = request.url;
      const fileName = url.substring(url.lastIndexOf('/') + 1);
      // TODO use correct image dimensions
      return new Response(offlineImage(fileName, 1080, 610),
          { headers: { 'Content-Type': 'image/svg+xml' } }
      );
    });
  } else {
    // cache all other requests
    return toolbox.fastest(request, values);
  }
}

function shouldNotCache(request) {
  return IGNORED_URLS.some(url => request.url.indexOf(url) != -1);
}

toolbox.options.debug = true;
toolbox.router.default = toolbox.networkOnly;
toolbox.router.get('/(.*)', ampByExampleHandler, {origin: self.location.origin});
// cache first amp runtime
toolbox.router.get('/(.*)', toolbox.cacheFirst, {origin: 'https://cdn.ampproject.org'});
// cache first google fonts
toolbox.router.get('/(.+)', toolbox.cacheFirst, {origin: /https?:\/\/fonts.+/});

toolbox.precache(config.filesToCache);

// Cache the page registering the service worker. Without this, the
// "first" page the user visits is only cached on the second visit,
// since the first load is uncontrolled.
toolbox.precache(
  clients.matchAll({includeUncontrolled: true}).then(l => {
    return l.map(c => c.url);
  })
);

// Claim clients so that the very first page load is controlled by a service
// worker. (Important for responding correctly in offline state.)
self.addEventListener('activate', () => self.clients.claim());

// Make sure the SW the page we register() is the service we use.
self.addEventListener('install', () => self.skipWaiting());
<commit_msg>Use networkFirst for samples & AMP Runtime (#600)<commit_after>/**
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 **/

importScripts('/bower_components/sw-toolbox/sw-toolbox.js');

const config = {
  offlinePage: '/youre_offline/'
}

const IGNORED_URLS = ['shopping_cart']

config.filesToCache = [
    '/',
    '/components/amp-img/',
    '/components/amp-install-serviceworker/',
    config.offlinePage,
    '/img/offline.png',
    '/img/logo.svg',
    '/favicons/favicon.ico',
    '/favicons/favicon-230x230.png',
    '/favicons/favicon-96x96.png',
    '/favicons/android-chrome-36x36.png',
    '/favicons/android-chrome-72x72.png',
    '/img/ic_experiment_black_2x_web_18dp.png',
    '/img/ic_experiment_black_1x_web_18dp.png',
    '/img/ic_experiment_black_2x_web_24dp.png',
    '/img/ic_experiment_black_1x_web_24dp.png',
    '/img/ic_experiment_black_2x_web_36dp.png',
    '/img/ic_experiment_black_1x_web_36dp.png',
    '/img/ic_link_black_1x_web_18dp.png',
    '/img/ic_link_black_2x_web_18dp.png',
    '/img/ic_menu_white_1x_web_24dp.png',
    '/img/ic_menu_white_2x_web_24dp.png',
    '/img/ic_indeterminate_check_box_black_24dp_1x.png',
    '/img/ic_indeterminate_check_box_black_24dp_2x.png',
    '/img/ic_add_box_black_24dp_1x.png',
    '/img/ic_add_box_black_24dp_2x.png',
    '/img/ic_chevron_left_black_24dp_1x.png',
    '/img/ic_chevron_left_black_24dp_2x.png',
    '/img/ic_play_arrow_white_1x_web_24dp.png',
    '/img/ic_play_arrow_white_2x_web_24dp.png',
    '/img/ic_mode_edit_white_24dp_1x.png',
    '/img/ic_mode_edit_white_24dp_2x.png',
    '/img/GitHub-Mark-Light-32px.png',
    '/img/GitHub-Mark-Light-64px.png',
    '/playground/img/playground-logo.svg',
    '/playground/'
];

/**
 * Generates a placeholder SVG image of the given size.
 */
function offlineImage(name, width, height) {
  return `<?xml version="1.0"?>
<svg width="${width}" height="${height}" viewBox="0 0 ${width} ${height}" xmlns="http://www.w3.org/2000/svg" version="1.1">
  <g fill="none" fill-rule="evenodd"><path fill="#F8BBD0" d="M0 0h${width}v${height}H0z"/></g>
  <text text-anchor="middle" x="${Math.floor(width / 2)}" y="${Math.floor(height / 2)}">image offline (${name})</text>
<style><![CDATA[
text{
  font: 48px Roboto,Verdana, Helvetica, Arial, sans-serif;
}
]]></style>
</svg>`;
}
/**
 * Returns true if the Accept header contains the given content type string.
 */
function requestAccepts(request, contentType) {
  return request.headers.get('Accept').indexOf(contentType) != -1;
}

/**
 * ampbyexample.com fetch handler:
 *
 * - one-behind caching
 * - shows offline page
 * - generates placeholder image for unavailable images
 */
function ampByExampleHandler(request, values) {
  // for samples show offline page if offline and samples are not cached
  if (requestAccepts(request, 'text/html')) {
    // never use cached version for AMP CORS requests (e.g. amp-live-list) or pages that shouldn't be cached
    if (request.url.indexOf("__amp_source_origin") != -1 || shouldNotCache(request)) {
      return toolbox.networkOnly(request, values);
    }
    // network first, we always want to get the latest
    return toolbox.networkFirst(request, values).catch(function() {
      return toolbox.cacheOnly(new Request(config.offlinePage), values)
        .then(function(response) {
          return response || new Response('You\'re offline. Sorry.', {
            status: 500,
            statusText: 'Offline Page Missing'
          });
        });
    });
  }
  // always try to load images from the cache first
  // fallback to placeholder SVG image if offline and image not available
  if (requestAccepts(request, 'image/')) {
    return toolbox.cacheFirst(request, values).catch(function() {
      const url = request.url;
      const fileName = url.substring(url.lastIndexOf('/') + 1);
      // TODO use correct image dimensions
      return new Response(offlineImage(fileName, 1080, 610),
          { headers: { 'Content-Type': 'image/svg+xml' } }
      );
    });
  } else {
    // cache first for all other requests
    return toolbox.cacheFirst(request, values);
  }
}

function shouldNotCache(request) {
  return IGNORED_URLS.some(url => request.url.indexOf(url) != -1);
}

toolbox.options.debug = false;
toolbox.router.default = toolbox.networkFirst;
toolbox.router.get('/(.*)', ampByExampleHandler, {origin: self.location.origin});
// network first amp runtime
toolbox.router.get('/(.*)', toolbox.networkFirst, {origin: 'https://cdn.ampproject.org'});

toolbox.precache(config.filesToCache);

// Cache the page registering the service worker. Without this, the
// "first" page the user visits is only cached on the second visit,
// since the first load is uncontrolled.
toolbox.precache(
  clients.matchAll({includeUncontrolled: true}).then(l => {
    return l.map(c => c.url);
  })
);

// Claim clients so that the very first page load is controlled by a service
// worker. (Important for responding correctly in offline state.)
self.addEventListener('activate', () => self.clients.claim());

// Make sure the SW the page we register() is the service we use.
self.addEventListener('install', () => self.skipWaiting());
<|endoftext|>


<commit_before><commit_msg>Cleanup JS files<commit_after><|endoftext|>


<commit_before><commit_msg>changed server-side React rendering times in ms<commit_after><|endoftext|>


<commit_before><commit_msg>revert the interceptor improvement because sometimes it causes an infinite loop<commit_after><|endoftext|>