<commit_before>import styled from 'styled-components'
import {
  scale,
  theme,
  StyledScrollbar
} from 'tocco-ui'
import {StyledLayoutBox} from 'tocco-ui/src/Layout'

import {StyledTitleWrapper} from '../../components/TitleMessage'
import {StyledCloseButton} from './ModalContent'

export const basePadding = scale.space(0.5)

const StyledModalContent = styled.div.attrs(({isClosing}) => ({
  className: `rrt-confirm animated ${isClosing ? 'fadeOut' : 'fadeIn'}`
}))`
  &&& {
    display: flex;
    flex-direction: column;
    background-color: ${theme.color('paper')};          // reset: react-redux-toastr (confirm.scss)
    border-radius: 0;           // reset: react-redux-toastr (confirm.scss)
    box-shadow: 2px 2px 10px rgba(0, 0, 0, .4);         // reset: react-redux-toastr (confirm.scss)
    padding: 0 ${basePadding} ${basePadding}; // reset: react-redux-toastr (confirm.scss)
    width: fit-content;
    min-width: 200px;
    ${StyledScrollbar}
    margin: auto;
    left: 0;
    right: 0;

    ${StyledCloseButton} {
      top: ${basePadding}px;  // reset
    }

    ${/* sc-selector */StyledTitleWrapper},
    .advanced-search-button-wrapper {
      box-sizing: border-box;
      background: ${theme.color('paper')};
      padding-top: ${basePadding};
      padding-bottom: ${scale.space(0.2)};
      width: 100%;
      z-index: 1;
    }

    ${StyledTitleWrapper} {
      width: auto;
    }

    .advanced-search-button-wrapper {
      position: sticky;
      bottom: 0;
      transform: translateY(1.8rem);
    }

    .button-wrapper {
      position: sticky;
      bottom: 0;
      padding-top: ${scale.space(0)};
      padding-bottom: ${basePadding};
      background-color: ${theme.color('paper')};
      transform: translateY(1.8rem);
    }

    ${StyledLayoutBox} {
      &:first-child {
        margin-top: ${scale.space(0)};
      }
    }
  }
`

export {
  StyledModalContent
}
<commit_msg>refactor(app-extensions): restrict modal width<commit_after>import styled from 'styled-components'
import {
  scale,
  theme,
  StyledScrollbar
} from 'tocco-ui'
import {StyledLayoutBox} from 'tocco-ui/src/Layout'

import {StyledTitleWrapper} from '../../components/TitleMessage'
import {StyledCloseButton} from './ModalContent'

export const basePadding = scale.space(0.5)

const StyledModalContent = styled.div.attrs(({isClosing}) => ({
  className: `rrt-confirm animated ${isClosing ? 'fadeOut' : 'fadeIn'}`
}))`
  &&& {
    display: flex;
    flex-direction: column;
    background-color: ${theme.color('paper')};          // reset: react-redux-toastr (confirm.scss)
    border-radius: 0;           // reset: react-redux-toastr (confirm.scss)
    box-shadow: 2px 2px 10px rgba(0, 0, 0, .4);         // reset: react-redux-toastr (confirm.scss)
    padding: 0 ${basePadding} ${basePadding}; // reset: react-redux-toastr (confirm.scss)
    width: fit-content;
    min-width: 350px;
    max-width: 700px;
    ${StyledScrollbar}
    margin: auto;
    left: 0;
    right: 0;

    ${StyledCloseButton} {
      top: ${basePadding}px;  // reset
    }

    ${/* sc-selector */StyledTitleWrapper},
    .advanced-search-button-wrapper {
      box-sizing: border-box;
      background: ${theme.color('paper')};
      padding-top: ${basePadding};
      padding-bottom: ${scale.space(0.2)};
      width: 100%;
      z-index: 1;
    }

    ${StyledTitleWrapper} {
      width: auto;
    }

    .advanced-search-button-wrapper {
      position: sticky;
      bottom: 0;
      transform: translateY(1.8rem);
    }

    .button-wrapper {
      position: sticky;
      bottom: 0;
      padding-top: ${scale.space(0)};
      padding-bottom: ${basePadding};
      background-color: ${theme.color('paper')};
      transform: translateY(1.8rem);
    }

    ${StyledLayoutBox} {
      &:first-child {
        margin-top: ${scale.space(0)};
      }
    }
  }
`

export {
  StyledModalContent
}
<|endoftext|>


<commit_before>// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Flags: --allow-natives-syntax --turbo-filter=*

function foo() {
  with ({ value:"fooed" }) { return value; }
}

%OptimizeFunctionOnNextCall(foo);
assertEquals("fooed", foo());
// TODO(mstarzinger): Still not optimized, make sure it is.
// assertOptimized(foo);

function bar() {
  with ({ value:"bared" }) { return value; }
}

assertEquals("bared", bar());
%OptimizeFunctionOnNextCall(bar);
assertEquals("bared", bar());
// TODO(mstarzinger): Still not optimized, make sure it is.
// assertOptimized(bar);
<commit_msg>Enable test coverage for test coverage.<commit_after>// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Flags: --allow-natives-syntax --turbo-filter=*

function foo() {
  with ({ value:"fooed" }) { return value; }
}

%OptimizeFunctionOnNextCall(foo);
assertEquals("fooed", foo());
assertOptimized(foo);

function bar() {
  with ({ value:"bared" }) { return value; }
}

assertEquals("bared", bar());
%OptimizeFunctionOnNextCall(bar);
assertEquals("bared", bar());
assertOptimized(bar);
<|endoftext|>


<commit_before>// 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([
  "app",
  "api",
  "cloudant.pagingcollection"
],

function(app, FauxtonAPI, PagingCollection) {
  var Documents = FauxtonAPI.addon();

  Documents.QueryParams = (function () {
    var _eachParams = function (params, action) {
      _.each(['startkey', 'endkey', 'key'], function (key) {
        if (_.has(params, key)) {
          params[key] = action(params[key]);
        }
      });

      return params;
    };

    return {
      parse: function (params) {
        return _eachParams(params, JSON.parse);
      },

      stringify: function (params) {
        return _eachParams(params, JSON.stringify);
      }
    };
  })();

  Documents.Doc = FauxtonAPI.Model.extend({
    idAttribute: "_id",
    documentation: function(){
      return "docs";
    },
    url: function(context) {
      if (context === "app") {
        return this.getDatabase().url("app") + "/" + this.safeID();
      } else if (context === "web-index") {
        return this.getDatabase().url("app") + "/" + app.utils.safeURLName(this.id);
      } else if (context === "apiurl"){
        return window.location.origin + "/" + this.getDatabase().safeID() + "/" + this.safeID();
      } else {
        return app.host + "/" + this.getDatabase().safeID() + "/" + this.safeID();
      }
    },

    initialize: function(_attrs, options) {
      if (this.collection && this.collection.database) {
        this.database = this.collection.database;
      } else if (options.database) {
        this.database = options.database;
      }
    },

    // HACK: the doc needs to know about the database, but it may be
    // set directly or indirectly in all docs
    getDatabase: function() {
      return this.database ? this.database : this.collection.database;
    },

    validate: function(attrs, options) {
      if (this.id && this.id !== attrs._id && this.get('_rev') ) {
        return "Cannot change a documents id.";
      }
    },

    docType: function() {
      return this.id && this.id.match(/^_design\//) ? "design doc" : "doc";
    },

    isEditable: function() {
      return this.docType() != "reduction";
    },

    isDdoc: function() {
      return this.docType() === "design doc";
    },

    hasViews: function() {
      if (!this.isDdoc()) return false;
      var doc = this.get('doc');
      if (doc) {
        return doc && doc.views && _.keys(doc.views).length > 0;
      }

      var views = this.get('views');
      return views && _.keys(views).length > 0;
    },

    hasAttachments: function () {
      return !!this.get('_attachments');
    },

    getDdocView: function(view) {
      if (!this.isDdoc() || !this.hasViews()) return false;

      var doc = this.get('doc');
      if (doc) {
        return doc.views[view];
      }

      return this.get('views')[view];
    },

    setDdocView: function (view, map, reduce) {
      if (!this.isDdoc()) return false;
      var views = this.get('views'),
          tempView = views[view] || {};

      if (reduce) {
        tempView.reduce=reduce;
      } else {
        delete tempView.reduce;
      }
      tempView.map= map;

      views[view] = tempView;
      this.set({views: views});

      return true;
    },

    removeDdocView: function (viewName) {
      if (!this.isDdoc()) return false;
      var views = this.get('views');

      delete views[viewName];
      this.set({views: views});
    },

    dDocModel: function () {
      if (!this.isDdoc()) return false;
      var doc = this.get('doc');

      if (doc) {
        return new Documents.Doc(doc, {database: this.database});
      }

      return this;
    },

    viewHasReduce: function(viewName) {
      var view = this.getDdocView(viewName);

      return view && view.reduce;
    },

    // Need this to work around backbone router thinking _design/foo
    // is a separate route. Alternatively, maybe these should be
    // treated separately. For instance, we could default into the
    // json editor for docs, or into a ddoc specific page.
    safeID: function() {
      if (this.isDdoc()){
        var ddoc = this.id.replace(/^_design\//,"");
        return "_design/"+app.utils.safeURLName(ddoc);
      }else{
        return app.utils.safeURLName(this.id);
      }
    },

    destroy: function() {
      var url = this.url() + "?rev=" + this.get('_rev');
      return $.ajax({
        url: url,
        dataType: 'json',
        type: 'DELETE'
      });
    },

    parse: function(resp) {
      if (resp.rev) {
        resp._rev = resp.rev;
        delete resp.rev;
      }
      if (resp.id) {
        if (typeof(this.id) === "undefined") {
          resp._id = resp.id;
        }
      }
      if (resp.ok) {
        delete resp.ok;
      }
      return resp;
    },

    prettyJSON: function() {
      var data = this.get("doc") ? this.get("doc") : this;

      return JSON.stringify(data, null, "  ");
    },

    copy: function (copyId) {
      return $.ajax({
        type: 'COPY',
        url: '/' + this.database.safeID() + '/' + this.safeID(),
        headers: {Destination: copyId}
      });
    },

    isNewDoc: function () {
      return this.get('_rev') ? false : true;
    }
  });

  Documents.DdocInfo = FauxtonAPI.Model.extend({
    idAttribute: "_id",
    documentation: function(){
      return "docs";
    },
    initialize: function (_attrs, options) {
      this.database = options.database;
    },

    url: function(context) {
      if (context === "app") {
        return this.database.url("app") + "/" + this.safeID() + '/_info';
      } else if (context === "apiurl"){
        return window.location.origin + "/" + this.database.safeID() + "/" + this.safeID() + '/_info';
      } else {
        return app.host + "/" + this.database.safeID() + "/" + this.safeID() + '/_info';
      }
    },

    // Need this to work around backbone router thinking _design/foo
    // is a separate route. Alternatively, maybe these should be
    // treated separately. For instance, we could default into the
    // json editor for docs, or into a ddoc specific page.
    safeID: function() {
      var ddoc = this.id.replace(/^_design\//,"");
      return "_design/"+app.utils.safeURLName(ddoc);
    }

  });

  Documents.ViewRow = FauxtonAPI.Model.extend({
    // this is a hack so that backbone.collections doesn't group
    // these by id and reduce the number of items returned.
    idAttribute: "_id",

    docType: function() {
      if (!this.id) return "reduction";

      return this.id.match(/^_design/) ? "design doc" : "doc";
    },
    documentation: function(){
      return "docs";
    },
    url: function(context) {
      return this.collection.database.url(context) + "/" + this.safeID();
    },

    isEditable: function() {
      return this.docType() != "reduction";
    },
    safeID: function() {
      var id = this.id || this.get("id");

      return app.utils.safeURLName(id);
    },

    prettyJSON: function() {
      //var data = this.get("doc") ? this.get("doc") : this;
      return JSON.stringify(this, null, "  ");
    }
  });

  Documents.NewDoc = Documents.Doc.extend({
    fetch: function() {
      var uuid = new FauxtonAPI.UUID();
      var deferred = this.deferred = $.Deferred();
      var that = this;

      uuid.fetch().done(function() {
        that.set("_id", uuid.next());
        deferred.resolve();
      });

      return deferred.promise();
    }

  });

  Documents.AllDocs = PagingCollection.extend({
    model: Documents.Doc,
    documentation: function(){
      return "docs";
    },
    initialize: function(_models, options) {
      this.database = options.database;
      this.params = _.clone(options.params);

      this.on("remove",this.decrementTotalRows , this);
      this.perPageLimit = options.perPageLimit || 20;

      if (!this.params.limit) {
        this.params.limit = this.perPageLimit;
      }
    },

    urlRef: function(context, params) {
      var query = "";

      if (params) {
        if (!_.isEmpty(params)) {
          query = "?" + $.param(params);
        } else {
          query = '';
        }
      } else if (this.params) {
        query = "?" + $.param(this.params);
      }

      if (context === 'app') {
        return 'database/' + this.database.safeID() + "/_all_docs" + query;
      } else if (context === "apiurl"){
        return window.location.origin + "/" + this.database.safeID() + "/_all_docs" + query;
      } else {
        return app.host + "/" + this.database.safeID() + "/_all_docs" + query;
      }
    },

    url: function () {
      return this.urlRef.apply(this, arguments);
    },

    simple: function () {
      var docs = this.map(function (item) {
        return {
          _id: item.id,
          _rev: item.get('_rev'),
        };
      });

      return new Documents.AllDocs(docs, {
        database: this.database,
        params: this.params
      });
    },

    totalRows: function() {
      return this.viewMeta.total_rows || "unknown";
    },

    decrementTotalRows: function () {
      if (this.viewMeta.total_rows) {
        this.viewMeta.total_rows = this.viewMeta.total_rows -1;
        this.trigger('totalRows:decrement');
      }
    },

    updateSeq: function() {
      return this.viewMeta.update_seq || false;
    },

    parse: function(resp) {
      var rows = resp.rows;

      // remove any query errors that may return without doc info
      // important for when querying keys on all docs
      resp.rows = _.filter(rows, function(row){
        return row.value;
      });

      return PagingCollection.prototype.parse.call(this, resp);
    }
  });

  Documents.IndexCollection = PagingCollection.extend({
    model: Documents.ViewRow,
    documentation: function(){
      return "docs";
    },
    initialize: function(_models, options) {
      this.database = options.database;
      this.params = _.extend({limit: 20, reduce: false}, options.params);

      this.idxType = "_view";
      this.view = options.view;
      this.design = options.design.replace('_design/','');
      this.perPageLimit = options.perPageLimit || 20;

      if (!this.params.limit) {
        this.params.limit = this.perPageLimit;
      }
    },

    urlRef: function(context, params) {
      var query = "";
      if (params) {
        if (!_.isEmpty(params)) {
          query = "?" + $.param(params);
        } else {
          query = '';
        }
      } else if (this.params) {
        query = "?" + $.param(this.params);
      }

      var startOfUrl = app.host;
      if (context === 'app') {
        startOfUrl = 'database';
      } else if (context === "apiurl"){
        startOfUrl = window.location.origin;
      }
      var design = app.utils.safeURLName(this.design),
          view = app.utils.safeURLName(this.view);

      var url = [startOfUrl, this.database.safeID(), "_design", design, this.idxType, view];
      return url.join("/") + query;
    },

    url: function () {
      return this.urlRef.apply(this, arguments);
    },

    totalRows: function() {
      if (this.params.reduce) { return "unknown_reduce";}

      return this.viewMeta.total_rows || "unknown";
    },

    updateSeq: function() {
      return this.viewMeta.update_seq || false;
    },

    simple: function () {
      var docs = this.map(function (item) {
        return {
          _id: item.id,
          key: item.get('key'),
          value: item.get('value')
        };
      });

      return new Documents.IndexCollection(docs, {
        database: this.database,
        params: this.params,
        view: this.view,
        design: this.design
      });
    },

    parse: function(resp) {
      var rows = resp.rows;
      this.endTime = new Date().getTime();
      this.requestDuration = (this.endTime - this.startTime);

      return PagingCollection.prototype.parse.apply(this, arguments);
    },

    buildAllDocs: function(){
      this.fetch();
    },

    // We implement our own fetch to store the starttime so we that
    // we can get the request duration
    fetch: function () {
      this.startTime = new Date().getTime();
      return PagingCollection.prototype.fetch.call(this);
    },

    allDocs: function(){
      return this.models;
    },

    // This is taken from futon.browse.js $.timeString
    requestDurationInString: function () {
      var ms, sec, min, h, timeString, milliseconds = this.requestDuration;

      sec = Math.floor(milliseconds / 1000.0);
      min = Math.floor(sec / 60.0);
      sec = (sec % 60.0).toString();
      if (sec.length < 2) {
         sec = "0" + sec;
      }

      h = (Math.floor(min / 60.0)).toString();
      if (h.length < 2) {
        h = "0" + h;
      }

      min = (min % 60.0).toString();
      if (min.length < 2) {
        min = "0" + min;
      }

      timeString = h + ":" + min + ":" + sec;

      ms = (milliseconds % 1000.0).toString();
      while (ms.length < 3) {
        ms = "0" + ms;
      }
      timeString += "." + ms;

      return timeString;
    }

  });

  Documents.PouchIndexCollection = PagingCollection.extend({
    model: Documents.ViewRow,
    documentation: function(){
      return "docs";
    },
    initialize: function(_models, options) {
      this.database = options.database;
      this.rows = options.rows;
      this.view = options.view;
      this.design = options.design.replace('_design/','');
      this.params = _.extend({limit: 20, reduce: false}, options.params);

      this.idxType = "_view";
    },

    url: function () {
      return '';
    },

    simple: function () {
      var docs = this.map(function (item) {
        return {
          _id: item.id,
          key: item.get('key'),
          value: item.get('value')
        };
      });

      return new Documents.PouchIndexCollection(docs, {
        database: this.database,
        params: this.params,
        view: this.view,
        design: this.design,
        rows: this.rows
      });

    },

    fetch: function() {
      var deferred = FauxtonAPI.Deferred();
      this.reset(this.rows, {silent: true});

      this.viewMeta = {
        total_rows: this.rows.length,
        offset: 0,
        update_seq: false
      };

      deferred.resolve();
      return deferred;
    },

    totalRows: function() {
      return this.viewMeta.total_rows || "unknown";
    },

    updateSeq: function() {
      return this.viewMeta.update_seq || false;
    },

    buildAllDocs: function(){
      this.fetch();
    },

    allDocs: function(){
      return this.models;
    }
  });

  return Documents;
});
<commit_msg>Fix bug in docs list<commit_after>// 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([
  "app",
  "api",
  "cloudant.pagingcollection"
],

function(app, FauxtonAPI, PagingCollection) {
  var Documents = FauxtonAPI.addon();

  Documents.QueryParams = (function () {
    var _eachParams = function (params, action) {
      _.each(['startkey', 'endkey', 'key'], function (key) {
        if (_.has(params, key)) {
          params[key] = action(params[key]);
        }
      });

      return params;
    };

    return {
      parse: function (params) {
        return _eachParams(params, JSON.parse);
      },

      stringify: function (params) {
        return _eachParams(params, JSON.stringify);
      }
    };
  })();

  Documents.Doc = FauxtonAPI.Model.extend({
    idAttribute: "_id",
    documentation: function(){
      return "docs";
    },
    url: function(context) {
      if (context === "app") {
        return this.getDatabase().url("app") + "/" + this.safeID();
      } else if (context === "web-index") {
        return this.getDatabase().url("app") + "/" + app.utils.safeURLName(this.id);
      } else if (context === "apiurl"){
        return window.location.origin + "/" + this.getDatabase().safeID() + "/" + this.safeID();
      } else {
        return app.host + "/" + this.getDatabase().safeID() + "/" + this.safeID();
      }
    },

    initialize: function(_attrs, options) {
      if (this.collection && this.collection.database) {
        this.database = this.collection.database;
      } else if (options.database) {
        this.database = options.database;
      }
    },

    // HACK: the doc needs to know about the database, but it may be
    // set directly or indirectly in all docs
    getDatabase: function() {
      return this.database ? this.database : this.collection.database;
    },

    validate: function(attrs, options) {
      if (this.id && this.id !== attrs._id && this.get('_rev') ) {
        return "Cannot change a documents id.";
      }
    },

    docType: function() {
      return this.id && this.id.match(/^_design\//) ? "design doc" : "doc";
    },

    isEditable: function() {
      return this.docType() != "reduction";
    },

    isDdoc: function() {
      return this.docType() === "design doc";
    },

    hasViews: function() {
      if (!this.isDdoc()) return false;
      var doc = this.get('doc');
      if (doc) {
        return doc && doc.views && _.keys(doc.views).length > 0;
      }

      var views = this.get('views');
      return views && _.keys(views).length > 0;
    },

    hasAttachments: function () {
      return !!this.get('_attachments');
    },

    getDdocView: function(view) {
      if (!this.isDdoc() || !this.hasViews()) return false;

      var doc = this.get('doc');
      if (doc) {
        return doc.views[view];
      }

      return this.get('views')[view];
    },

    setDdocView: function (view, map, reduce) {
      if (!this.isDdoc()) return false;
      var views = this.get('views'),
          tempView = views[view] || {};

      if (reduce) {
        tempView.reduce=reduce;
      } else {
        delete tempView.reduce;
      }
      tempView.map= map;

      views[view] = tempView;
      this.set({views: views});

      return true;
    },

    removeDdocView: function (viewName) {
      if (!this.isDdoc()) return false;
      var views = this.get('views');

      delete views[viewName];
      this.set({views: views});
    },

    dDocModel: function () {
      if (!this.isDdoc()) return false;
      var doc = this.get('doc');

      if (doc) {
        return new Documents.Doc(doc, {database: this.database});
      }

      return this;
    },

    viewHasReduce: function(viewName) {
      var view = this.getDdocView(viewName);

      return view && view.reduce;
    },

    // Need this to work around backbone router thinking _design/foo
    // is a separate route. Alternatively, maybe these should be
    // treated separately. For instance, we could default into the
    // json editor for docs, or into a ddoc specific page.
    safeID: function() {
      if (this.isDdoc()){
        var ddoc = this.id.replace(/^_design\//,"");
        return "_design/"+app.utils.safeURLName(ddoc);
      }else{
        return app.utils.safeURLName(this.id);
      }
    },

    destroy: function() {
      var url = this.url() + "?rev=" + this.get('_rev');
      return $.ajax({
        url: url,
        dataType: 'json',
        type: 'DELETE'
      });
    },

    parse: function(resp) {
      if (resp.rev) {
        resp._rev = resp.rev;
        delete resp.rev;
      }
      if (resp.id) {
        if (typeof(this.id) === "undefined") {
          resp._id = resp.id;
        }
      }
      if (resp.ok) {
        delete resp.ok;
      }
      return resp;
    },

    prettyJSON: function() {
      var data = this.get("doc") ? this.get("doc") : this;

      return JSON.stringify(data, null, "  ");
    },

    copy: function (copyId) {
      return $.ajax({
        type: 'COPY',
        url: '/' + this.database.safeID() + '/' + this.safeID(),
        headers: {Destination: copyId}
      });
    },

    isNewDoc: function () {
      return this.get('_rev') ? false : true;
    }
  });

  Documents.DdocInfo = FauxtonAPI.Model.extend({
    idAttribute: "_id",
    documentation: function(){
      return "docs";
    },
    initialize: function (_attrs, options) {
      this.database = options.database;
    },

    url: function(context) {
      if (context === "app") {
        return this.database.url("app") + "/" + this.safeID() + '/_info';
      } else if (context === "apiurl"){
        return window.location.origin + "/" + this.database.safeID() + "/" + this.safeID() + '/_info';
      } else {
        return app.host + "/" + this.database.safeID() + "/" + this.safeID() + '/_info';
      }
    },

    // Need this to work around backbone router thinking _design/foo
    // is a separate route. Alternatively, maybe these should be
    // treated separately. For instance, we could default into the
    // json editor for docs, or into a ddoc specific page.
    safeID: function() {
      var ddoc = this.id.replace(/^_design\//,"");
      return "_design/"+app.utils.safeURLName(ddoc);
    }

  });

  Documents.ViewRow = FauxtonAPI.Model.extend({
    // this is a hack so that backbone.collections doesn't group
    // these by id and reduce the number of items returned.
    idAttribute: "_id",

    docType: function() {
      if (!this.id) return "reduction";

      return this.id.match(/^_design/) ? "design doc" : "doc";
    },
    documentation: function(){
      return "docs";
    },
    url: function(context) {
      return this.collection.database.url(context) + "/" + this.safeID();
    },

    isEditable: function() {
      return this.docType() != "reduction";
    },
    safeID: function() {
      var id = this.id || this.get("id");

      return app.utils.safeURLName(id);
    },

    prettyJSON: function() {
      //var data = this.get("doc") ? this.get("doc") : this;
      return JSON.stringify(this, null, "  ");
    }
  });

  Documents.NewDoc = Documents.Doc.extend({
    fetch: function() {
      var uuid = new FauxtonAPI.UUID();
      var deferred = this.deferred = $.Deferred();
      var that = this;

      uuid.fetch().done(function() {
        that.set("_id", uuid.next());
        deferred.resolve();
      });

      return deferred.promise();
    }

  });

  Documents.AllDocs = PagingCollection.extend({
    model: Documents.Doc,
    documentation: function(){
      return "docs";
    },
    initialize: function(_models, options) {
      this.database = options.database;
      this.params = _.clone(options.params);

      this.on("remove",this.decrementTotalRows , this);
      this.perPageLimit = options.perPageLimit || 20;

      if (!this.params.limit) {
        this.params.limit = this.perPageLimit;
      }
    },

    urlRef: function(context, params) {
      var query = "";

      if (params) {
        if (!_.isEmpty(params)) {
          query = "?" + $.param(params);
        } else {
          query = '';
        }
      } else if (this.params) {
        query = "?" + $.param(this.params);
      }

      if (context === 'app') {
        return 'database/' + this.database.safeID() + "/_all_docs" + query;
      } else if (context === "apiurl"){
        return window.location.origin + "/" + this.database.safeID() + "/_all_docs" + query;
      } else {
        return app.host + "/" + this.database.safeID() + "/_all_docs" + query;
      }
    },

    url: function () {
      return this.urlRef.apply(this, arguments);
    },

    simple: function () {
      var docs = this.map(function (item) {
        return {
          _id: item.id,
          _rev: item.get('_rev'),
        };
      });

      return new Documents.AllDocs(docs, {
        database: this.database,
        params: this.params
      });
    },

    totalRows: function() {
      return this.viewMeta.total_rows || "unknown";
    },

    decrementTotalRows: function () {
      if (this.viewMeta.total_rows) {
        this.viewMeta.total_rows = this.viewMeta.total_rows -1;
        this.trigger('totalRows:decrement');
      }
    },

    updateSeq: function() {
      return this.viewMeta.update_seq || false;
    },

    parse: function(resp) {
      var rows = resp.rows;

      // remove any query errors that may return without doc info
      // important for when querying keys on all docs
      var cleanRows = _.filter(rows, function(row){
        return row.value;
      });

      resp.rows = _.map(cleanRows, function(row){
        return {
          _id: row.id,
          _rev: row.value.rev,
          value: row.value,
          key: row.key,
          doc: row.doc || undefined
        };
      });

      return PagingCollection.prototype.parse.call(this, resp);
    }
  });

  Documents.IndexCollection = PagingCollection.extend({
    model: Documents.ViewRow,
    documentation: function(){
      return "docs";
    },
    initialize: function(_models, options) {
      this.database = options.database;
      this.params = _.extend({limit: 20, reduce: false}, options.params);

      this.idxType = "_view";
      this.view = options.view;
      this.design = options.design.replace('_design/','');
      this.perPageLimit = options.perPageLimit || 20;

      if (!this.params.limit) {
        this.params.limit = this.perPageLimit;
      }
    },

    urlRef: function(context, params) {
      var query = "";
      if (params) {
        if (!_.isEmpty(params)) {
          query = "?" + $.param(params);
        } else {
          query = '';
        }
      } else if (this.params) {
        query = "?" + $.param(this.params);
      }

      var startOfUrl = app.host;
      if (context === 'app') {
        startOfUrl = 'database';
      } else if (context === "apiurl"){
        startOfUrl = window.location.origin;
      }
      var design = app.utils.safeURLName(this.design),
          view = app.utils.safeURLName(this.view);

      var url = [startOfUrl, this.database.safeID(), "_design", design, this.idxType, view];
      return url.join("/") + query;
    },

    url: function () {
      return this.urlRef.apply(this, arguments);
    },

    totalRows: function() {
      if (this.params.reduce) { return "unknown_reduce";}

      return this.viewMeta.total_rows || "unknown";
    },

    updateSeq: function() {
      return this.viewMeta.update_seq || false;
    },

    simple: function () {
      var docs = this.map(function (item) {
        return {
          _id: item.id,
          key: item.get('key'),
          value: item.get('value')
        };
      });

      return new Documents.IndexCollection(docs, {
        database: this.database,
        params: this.params,
        view: this.view,
        design: this.design
      });
    },

    parse: function(resp) {
      var rows = resp.rows;
      this.endTime = new Date().getTime();
      this.requestDuration = (this.endTime - this.startTime);

      return PagingCollection.prototype.parse.apply(this, arguments);
    },

    buildAllDocs: function(){
      this.fetch();
    },

    // We implement our own fetch to store the starttime so we that
    // we can get the request duration
    fetch: function () {
      this.startTime = new Date().getTime();
      return PagingCollection.prototype.fetch.call(this);
    },

    allDocs: function(){
      return this.models;
    },

    // This is taken from futon.browse.js $.timeString
    requestDurationInString: function () {
      var ms, sec, min, h, timeString, milliseconds = this.requestDuration;

      sec = Math.floor(milliseconds / 1000.0);
      min = Math.floor(sec / 60.0);
      sec = (sec % 60.0).toString();
      if (sec.length < 2) {
         sec = "0" + sec;
      }

      h = (Math.floor(min / 60.0)).toString();
      if (h.length < 2) {
        h = "0" + h;
      }

      min = (min % 60.0).toString();
      if (min.length < 2) {
        min = "0" + min;
      }

      timeString = h + ":" + min + ":" + sec;

      ms = (milliseconds % 1000.0).toString();
      while (ms.length < 3) {
        ms = "0" + ms;
      }
      timeString += "." + ms;

      return timeString;
    }

  });

  Documents.PouchIndexCollection = PagingCollection.extend({
    model: Documents.ViewRow,
    documentation: function(){
      return "docs";
    },
    initialize: function(_models, options) {
      this.database = options.database;
      this.rows = options.rows;
      this.view = options.view;
      this.design = options.design.replace('_design/','');
      this.params = _.extend({limit: 20, reduce: false}, options.params);

      this.idxType = "_view";
    },

    url: function () {
      return '';
    },

    simple: function () {
      var docs = this.map(function (item) {
        return {
          _id: item.id,
          key: item.get('key'),
          value: item.get('value')
        };
      });

      return new Documents.PouchIndexCollection(docs, {
        database: this.database,
        params: this.params,
        view: this.view,
        design: this.design,
        rows: this.rows
      });

    },

    fetch: function() {
      var deferred = FauxtonAPI.Deferred();
      this.reset(this.rows, {silent: true});

      this.viewMeta = {
        total_rows: this.rows.length,
        offset: 0,
        update_seq: false
      };

      deferred.resolve();
      return deferred;
    },

    totalRows: function() {
      return this.viewMeta.total_rows || "unknown";
    },

    updateSeq: function() {
      return this.viewMeta.update_seq || false;
    },

    buildAllDocs: function(){
      this.fetch();
    },

    allDocs: function(){
      return this.models;
    }
  });

  return Documents;
});
<|endoftext|>


<commit_before>import React, { useRef } from 'react';
import { useIntl } from 'react-intl';
import { useCMEditViewDataManager } from '@strapi/helper-plugin';
import { Box } from '@strapi/design-system/Box';
import { Divider } from '@strapi/design-system/Divider';
import { Typography } from '@strapi/design-system/Typography';
import { Flex } from '@strapi/design-system/Flex';
import { Stack } from '@strapi/design-system/Stack';
import { getTrad } from '../../../utils';
import getUnits from './utils/getUnits';
import { getFullName } from '../../../../utils';

const Informations = () => {
  const { formatMessage, formatRelativeTime } = useIntl();
  const { initialData, isCreatingEntry } = useCMEditViewDataManager();

  const updatedAt = 'updatedAt';
  const updatedByFirstname = initialData.updatedBy?.firstname || '';
  const updatedByLastname = initialData.updatedBy?.lastname || '';
  const updatedByUsername = initialData.updatedBy?.username;
  const updatedBy = updatedByUsername || getFullName(updatedByFirstname, updatedByLastname);
  const currentTime = useRef(Date.now());
  const timestamp = initialData[updatedAt]
    ? new Date(initialData[updatedAt]).getTime()
    : Date.now();
  const elapsed = timestamp - currentTime.current;

  const { unit, value } = getUnits(-elapsed);

  return (
    <Box>
      <Typography variant="sigma" textColor="neutral600" id="additional-informations">
        {formatMessage({
          id: getTrad('containers.Edit.information'),
          defaultMessage: 'Information',
        })}
      </Typography>
      <Box paddingTop={2} paddingBottom={6}>
        <Divider />
      </Box>
      <Stack size={4}>
        <Flex justifyContent="space-between">
          <Typography fontWeight="bold">
            {formatMessage({
              id: getTrad('containers.Edit.information.lastUpdate'),
              defaultMessage: 'Last update',
            })}
          </Typography>
          <Typography>{formatRelativeTime(value, unit, { numeric: 'auto' })}</Typography>
        </Flex>
        <Flex justifyContent="space-between">
          <Typography fontWeight="bold">
            {formatMessage({
              id: getTrad('containers.Edit.information.by'),
              defaultMessage: 'By',
            })}
          </Typography>
          <Typography>{isCreatingEntry ? '-' : updatedBy}</Typography>
        </Flex>
      </Stack>
    </Box>
  );
};

export default Informations;
<commit_msg>Extract how to get the update info to a function<commit_after>import React, { useRef } from 'react';
import { useIntl } from 'react-intl';
import { useCMEditViewDataManager } from '@strapi/helper-plugin';
import { Box } from '@strapi/design-system/Box';
import { Divider } from '@strapi/design-system/Divider';
import { Typography } from '@strapi/design-system/Typography';
import { Flex } from '@strapi/design-system/Flex';
import { Stack } from '@strapi/design-system/Stack';
import { getTrad } from '../../../utils';
import getUnits from './utils/getUnits';
import { getFullName } from '../../../../utils';

const Informations = () => {
  const { formatMessage, formatRelativeTime } = useIntl();
  const { initialData, isCreatingEntry } = useCMEditViewDataManager();
  const currentTime = useRef(Date.now());

  const getFieldInfo = (atField, byField) => {
    const userFirstname = initialData[byField]?.firstname || '';
    const userLastname = initialData[byField]?.lastname || '';
    const userUsername = initialData[byField]?.username;
    const user = userUsername || getFullName(userFirstname, userLastname);
    const timestamp = initialData[atField] ? new Date(initialData[atField]).getTime() : Date.now();
    const elapsed = timestamp - currentTime.current;
    const { unit, value } = getUnits(-elapsed);

    return {
      at: formatRelativeTime(value, unit, { numeric: 'auto' }),
      by: isCreatingEntry ? '-' : user,
    };
  };

  const updated = getFieldInfo('updatedAt', 'updatedBy');

  return (
    <Box>
      <Typography variant="sigma" textColor="neutral600" id="additional-informations">
        {formatMessage({
          id: getTrad('containers.Edit.information'),
          defaultMessage: 'Information',
        })}
      </Typography>
      <Box paddingTop={2} paddingBottom={6}>
        <Divider />
      </Box>
      <Stack size={4}>
        <Flex justifyContent="space-between">
          <Typography fontWeight="bold">
            {formatMessage({
              id: getTrad('containers.Edit.information.lastUpdate'),
              defaultMessage: 'Last update',
            })}
          </Typography>
          <Typography>{updated.at}</Typography>
        </Flex>
        <Flex justifyContent="space-between">
          <Typography fontWeight="bold">
            {formatMessage({
              id: getTrad('containers.Edit.information.by'),
              defaultMessage: 'By',
            })}
          </Typography>
          <Typography>{updated.by}</Typography>
        </Flex>
      </Stack>
    </Box>
  );
};

export default Informations;
<|endoftext|>


<commit_before>/* Tests the streaming xhr without stubbing anything. Really just a test that
*  we've got the interface of the in-browser XHR object pinned down  */

describe('streaming xhr integration (real http)', function() {
   "use strict";

   var requiredEvents = [HTTP_START, STREAM_DATA, STREAM_END, FAIL_EVENT, ABORTING];

   it('completes',  function() {

      // in practice, since we're running on an internal network and this is a small file,
      // we'll probably only get one callback
      var oboeBus = fakePubSub(requiredEvents)
      streamingHttp(
         oboeBus,
         httpTransport(),
         'GET',
         '/testServer/static/json/smallestPossible.json',
         null // this is a GET, no data to send
      );

      waitForStreamEndToBeFiredOn(oboeBus);
   })

   it('can ajax in a small known file',  function() {

      // in practice, since we're running on an internal network and this is a small file,
      // we'll probably only get one callback
      var oboeBus = fakePubSub(requiredEvents)
      streamingHttp(
         oboeBus,
         httpTransport(),
         'GET',
         '/testServer/static/json/smallestPossible.json',
         null // this is a GET, no data to send
      );

      waitForStreamEndToBeFiredOn(oboeBus);

      runs(function(){
         expect(oboeBus).toHaveGivenStreamEventsInCorrectOrder()
         expect(streamedContentPassedTo(oboeBus)).toParseTo({})
      });
   })

   it('fires HTTP_START with status and headers',  function() {

      var oboeBus = fakePubSub(requiredEvents)
      streamingHttp(
         oboeBus,
         httpTransport(),
         'GET',
         '/testServer/echoBackHeadersAsHeaders',
         null, // this is a GET, no data to send
         {'specialheader':'specialValue'}
      );

      waitForStreamEndToBeFiredOn(oboeBus);

      runs(function(){
         expect(oboeBus(HTTP_START).emit)
            .toHaveBeenCalledWith(
               200,
               headerObjectContaining('specialheader', 'specialValue')
            );
      });
   })

   it('gives XHR header so server knows this is an xhr request',  function() {

      var oboeBus = fakePubSub(requiredEvents)
      streamingHttp(
         oboeBus,
         httpTransport(),
         'GET',
         '/testServer/echoBackHeadersAsHeaders'
      );

      waitForStreamEndToBeFiredOn(oboeBus);

      runs(function(){
         expect(oboeBus(HTTP_START).emit)
            .toHaveBeenCalledWith(
               200,
               headerObjectContaining('X-Requested-With', 'XMLHttpRequest')
            );

         console.log(oboeBus(HTTP_START).emit.calls[0].args[1]);
      });

   })

   it('fires HTTP_START, STREAM_DATA and STREAM_END in correct order',  function() {

      // in practice, since we're running on an internal network and this is a small file,
      // we'll probably only get one callback
      var oboeBus = fakePubSub(requiredEvents)
      streamingHttp(
         oboeBus,
         httpTransport(),
         'GET',
         '/testServer/echoBackHeadersAsHeaders',
         null, // this is a GET, no data to send
         {'specialheader':'specialValue'}
      );

      waitForStreamEndToBeFiredOn(oboeBus);

      runs(function(){
         expect(oboeBus).toHaveGivenStreamEventsInCorrectOrder()
      });
   })

   it('can ajax in a very large file without missing any',  function() {

      // in practice, since we're running on an internal network and this is a small file,
      // we'll probably only get one callback
      var oboeBus = fakePubSub(requiredEvents)
      streamingHttp(
         oboeBus,
         httpTransport(),
         'GET',
         '/testServer/static/json/twentyThousandRecords.json',
         null // this is a GET, no data to send
      );

      waitForStreamEndToBeFiredOn(oboeBus);

      runs(function(){
         var parsedResult;

         expect(function(){

            parsedResult = JSON.parse(streamedContentPassedTo(oboeBus));

         }).not.toThrow();

         // as per the name, should have 20,000 records in that file:
         expect(parsedResult.result.length).toEqual(20000);
      });
   })

   it('can ajax in a streaming file without missing any',  function() {

      // in practice, since we're running on an internal network and this is a small file,
      // we'll probably only get one callback
      var oboeBus = fakePubSub(requiredEvents)
      streamingHttp(
         oboeBus,
         httpTransport(),
         'GET',
         '/testServer/tenSlowNumbers?withoutMissingAny',
          null // this is a GET, no data to send
      );

      waitForStreamEndToBeFiredOn(oboeBus);

      runs(function(){
         // as per the name, should have ten numbers in that file:
         expect(streamedContentPassedTo(oboeBus)).toParseTo([0,1,2,3,4,5,6,7,8,9]);
         expect(oboeBus).toHaveGivenStreamEventsInCorrectOrder()
      });
   })

   it('can make a post request',  function() {

      var payload = {'thisWill':'bePosted','andShould':'be','echoed':'back'};

      // in practice, since we're running on an internal network and this is a small file,
      // we'll probably only get one callback
      var oboeBus = fakePubSub(requiredEvents)
      streamingHttp(
         oboeBus,
         httpTransport(),
         'POST',
         '/testServer/echoBackBody',
         payload
      );

      waitForStreamEndToBeFiredOn(oboeBus);

      runs(function(){
         expect(streamedContentPassedTo(oboeBus)).toParseTo(payload);
         expect(oboeBus).toHaveGivenStreamEventsInCorrectOrder()
      });

   })

   it('can make a put request',  function() {

      var payload = {'thisWill':'bePut','andShould':'be','echoed':'back'};

      // in practice, since we're running on an internal network and this is a small file,
      // we'll probably only get one callback
      var oboeBus = fakePubSub(requiredEvents)
      streamingHttp(
         oboeBus,
         httpTransport(),
         'PUT',
          '/testServer/echoBackBody',
          payload
      );

      waitForStreamEndToBeFiredOn(oboeBus);

      runs(function(){
         expect(streamedContentPassedTo(oboeBus)).toParseTo(payload);
         expect(oboeBus).toHaveGivenStreamEventsInCorrectOrder()
      });

   })

   it('can make a patch request',  function() {

      var payload = {'thisWill':'bePatched','andShould':'be','echoed':'back'};

      // in practice, since we're running on an internal network and this is a small file,
      // we'll probably only get one callback
      var oboeBus = fakePubSub(requiredEvents)
      streamingHttp(
         oboeBus,
         httpTransport(),
         'PATCH',
          '/testServer/echoBackBody',
          payload
      );

      waitForStreamEndToBeFiredOn(oboeBus);

      runs(function(){
         if( streamedContentPassedTo(oboeBus) == '' &&
             (Platform.isInternetExplorer || Platform.isPhantom) ) {
            console.warn( 'this user agent seems not to support giving content'
                          + ' back for of PATCH requests.'
                          + ' This happens on PhantomJS and IE < 9');
         } else {
            expect(streamedContentPassedTo(oboeBus)).toParseTo(payload);
            expect(oboeBus).toHaveGivenStreamEventsInCorrectOrder();
         }
      });

   })

   // this test is only activated for non-IE browsers and IE 10 or newer.
   // old and rubbish browsers buffer the xhr response meaning that this
   // will never pass. But for good browsers it is good to have an integration
   // test to confirm that we're getting it right.
   if( !Platform.isInternetExplorer || Platform.isInternetExplorer >= 10 ) {
      it('gives multiple callbacks when loading a streaming resource',  function() {

         var oboeBus = fakePubSub(requiredEvents)
         streamingHttp(
            oboeBus,
            httpTransport(),
            'GET',

            '/testServer/tenSlowNumbers',
             null // this is a get: no data to send
         );

         waitForStreamEndToBeFiredOn(oboeBus);

         runs(function(){

            // realistically, should have had 10 or 20, but this isn't deterministic so
            // 3 is enough to indicate the results didn't all arrive in one big blob.
            expect(oboeBus.callCount[STREAM_DATA]).toBeGreaterThan(3)
            expect(oboeBus).toHaveGivenStreamEventsInCorrectOrder()
         });
      })

      it('gives multiple callbacks when loading a gzipped streaming resource',  function() {

         var oboeBus = fakePubSub(requiredEvents)
         streamingHttp(
            oboeBus,
            httpTransport(),
            'GET',

            '/testServer/gzippedTwoHundredItems',
             null // this is a get: no data to send
         );

         waitForStreamEndToBeFiredOn(oboeBus);

         runs(function(){
            // some platforms can't help but not work here so warn but don't
            // fail the test:
            if( oboeBus.callCount[STREAM_DATA] == 1 &&
                  (Platform.isInternetExplorer || Platform.isPhantom) ) {
               console.warn('This user agent seems to give gzipped responses' +
                   'as a single event, not progressively. This happens on ' +
                   'PhantomJS and IE < 9');
            } else {
               expect(oboeBus.callCount[STREAM_DATA]).toBeGreaterThan(1);
            }

            expect(oboeBus).toHaveGivenStreamEventsInCorrectOrder();
         });
      })
   }

   it('does not call back with zero-length data',  function() {

      // since this is a large file, even serving locally we're going to get multiple callbacks:
      var oboeBus = fakePubSub(requiredEvents)
      streamingHttp(
         oboeBus,
         httpTransport(),
         'GET',
         '/testServer/static/json/oneHundredRecords.json',
         null // this is a GET: no data to send
      );

      waitForStreamEndToBeFiredOn(oboeBus)

      runs(function(){

         var dripsReceived = oboeBus.eventTypesEmitted[STREAM_DATA].map(function( args ){
            return args[0];
         });

         expect(dripsReceived.length).toBeGreaterThan(0);

         dripsReceived.forEach(function(drip) {
            expect(drip.length).not.toEqual(0);
         });

      })
   })

   function waitForStreamEndToBeFiredOn(eventBus){
      waitsFor(function(){

         return !!eventBus(STREAM_END).emit.calls.length;

      }, 'streaming xhr to complete', ASYNC_TEST_TIMEOUT);
   }

   function streamedContentPassedTo(eventBus){

      return eventBus.eventTypesEmitted[STREAM_DATA].map(function(args){
         return args[0];
      }).join('');
   }

   beforeEach(function(){

      function prettyPrintEvent(event){

         switch(event) {
            case     HTTP_START:  return 'start';
            case     STREAM_DATA: return 'data';
            case     STREAM_END:  return 'end';
            default: return 'unknown(' + event + ')'
         }
      }

      this.addMatchers({
         toHaveGivenStreamEventsInCorrectOrder: function(){

            var eventNames = this.actual.eventNames;

            this.message = function(){
               return 'events not in correct order. We have: ' +
                        JSON.stringify(
                           eventNames.map(prettyPrintEvent)
                        )
            };

            return   eventNames[0] === HTTP_START
                  && eventNames[1] === STREAM_DATA
                  && eventNames[eventNames.length-1] === STREAM_END;
         },

         toParseTo:function( expectedObj ){

            var actual = this.actual;
            var normalisedActual;

            if( !actual ) {
               this.message = function(){
                  return 'no content has been received';
               }
               return false;
            }

            try{
               normalisedActual = JSON.stringify( JSON.parse(actual) );
            }catch(e){

               this.message = function(){

                  return "Expected to be able to parse the found " +
                      "content as json '" + actual + "' but it " +
                      "could not be parsed";
               }

               return false;
            }

            this.message = function(){
               return "The found json parsed but did not match " + JSON.stringify(expectedObj) +
                        " because found " + this.actual;
            }

            return (normalisedActual === JSON.stringify(expectedObj));
         }
      });

   });

   function headerObjectContaining(key, val) {
      // some browsers lowercase the header keys. Compare upper and lower
      // case versions:

      return {
         jasmineMatches: function(obj){
            return obj[key] == val || obj[key.toLowerCase()] == val;
         }
      }
   }

});<commit_msg>rename<commit_after>/* Tests the streaming xhr without stubbing anything. Really just a test that
*  we've got the interface of the in-browser XHR object pinned down  */

describe('streaming xhr integration (real http)', function() {
   "use strict";

   var emittedEvents = [HTTP_START, STREAM_DATA, STREAM_END, FAIL_EVENT, ABORTING];

   it('completes',  function() {

      // in practice, since we're running on an internal network and this is a small file,
      // we'll probably only get one callback
      var oboeBus = fakePubSub(emittedEvents)
      streamingHttp(
         oboeBus,
         httpTransport(),
         'GET',
         '/testServer/static/json/smallestPossible.json',
         null // this is a GET, no data to send
      );

      waitForStreamEndToBeFiredOn(oboeBus);
   })

   it('can ajax in a small known file',  function() {

      // in practice, since we're running on an internal network and this is a small file,
      // we'll probably only get one callback
      var oboeBus = fakePubSub(emittedEvents)
      streamingHttp(
         oboeBus,
         httpTransport(),
         'GET',
         '/testServer/static/json/smallestPossible.json',
         null // this is a GET, no data to send
      );

      waitForStreamEndToBeFiredOn(oboeBus);

      runs(function(){
         expect(oboeBus).toHaveGivenStreamEventsInCorrectOrder()
         expect(streamedContentPassedTo(oboeBus)).toParseTo({})
      });
   })

   it('fires HTTP_START with status and headers',  function() {

      var oboeBus = fakePubSub(emittedEvents)
      streamingHttp(
         oboeBus,
         httpTransport(),
         'GET',
         '/testServer/echoBackHeadersAsHeaders',
         null, // this is a GET, no data to send
         {'specialheader':'specialValue'}
      );

      waitForStreamEndToBeFiredOn(oboeBus);

      runs(function(){
         expect(oboeBus(HTTP_START).emit)
            .toHaveBeenCalledWith(
               200,
               headerObjectContaining('specialheader', 'specialValue')
            );
      });
   })

   it('gives XHR header so server knows this is an xhr request',  function() {

      var oboeBus = fakePubSub(emittedEvents)
      streamingHttp(
         oboeBus,
         httpTransport(),
         'GET',
         '/testServer/echoBackHeadersAsHeaders'
      );

      waitForStreamEndToBeFiredOn(oboeBus);

      runs(function(){
         expect(oboeBus(HTTP_START).emit)
            .toHaveBeenCalledWith(
               200,
               headerObjectContaining('X-Requested-With', 'XMLHttpRequest')
            );

         console.log(oboeBus(HTTP_START).emit.calls[0].args[1]);
      });

   })

   it('fires HTTP_START, STREAM_DATA and STREAM_END in correct order',  function() {

      // in practice, since we're running on an internal network and this is a small file,
      // we'll probably only get one callback
      var oboeBus = fakePubSub(emittedEvents)
      streamingHttp(
         oboeBus,
         httpTransport(),
         'GET',
         '/testServer/echoBackHeadersAsHeaders',
         null, // this is a GET, no data to send
         {'specialheader':'specialValue'}
      );

      waitForStreamEndToBeFiredOn(oboeBus);

      runs(function(){
         expect(oboeBus).toHaveGivenStreamEventsInCorrectOrder()
      });
   })

   it('fires FAIL_EVENT if connection is lost',  function() {
   })

   it('can ajax in a very large file without missing any',  function() {

      // in practice, since we're running on an internal network and this is a small file,
      // we'll probably only get one callback
      var oboeBus = fakePubSub(emittedEvents)
      streamingHttp(
         oboeBus,
         httpTransport(),
         'GET',
         '/testServer/static/json/twentyThousandRecords.json',
         null // this is a GET, no data to send
      );

      waitForStreamEndToBeFiredOn(oboeBus);

      runs(function(){
         var parsedResult;

         expect(function(){

            parsedResult = JSON.parse(streamedContentPassedTo(oboeBus));

         }).not.toThrow();

         // as per the name, should have 20,000 records in that file:
         expect(parsedResult.result.length).toEqual(20000);
      });
   })

   it('can ajax in a streaming file without missing any',  function() {

      // in practice, since we're running on an internal network and this is a small file,
      // we'll probably only get one callback
      var oboeBus = fakePubSub(emittedEvents)
      streamingHttp(
         oboeBus,
         httpTransport(),
         'GET',
         '/testServer/tenSlowNumbers?withoutMissingAny',
          null // this is a GET, no data to send
      );

      waitForStreamEndToBeFiredOn(oboeBus);

      runs(function(){
         // as per the name, should have ten numbers in that file:
         expect(streamedContentPassedTo(oboeBus)).toParseTo([0,1,2,3,4,5,6,7,8,9]);
         expect(oboeBus).toHaveGivenStreamEventsInCorrectOrder()
      });
   })

   it('can make a post request',  function() {

      var payload = {'thisWill':'bePosted','andShould':'be','echoed':'back'};

      // in practice, since we're running on an internal network and this is a small file,
      // we'll probably only get one callback
      var oboeBus = fakePubSub(emittedEvents)
      streamingHttp(
         oboeBus,
         httpTransport(),
         'POST',
         '/testServer/echoBackBody',
         payload
      );

      waitForStreamEndToBeFiredOn(oboeBus);

      runs(function(){
         expect(streamedContentPassedTo(oboeBus)).toParseTo(payload);
         expect(oboeBus).toHaveGivenStreamEventsInCorrectOrder()
      });

   })

   it('can make a put request',  function() {

      var payload = {'thisWill':'bePut','andShould':'be','echoed':'back'};

      // in practice, since we're running on an internal network and this is a small file,
      // we'll probably only get one callback
      var oboeBus = fakePubSub(emittedEvents)
      streamingHttp(
         oboeBus,
         httpTransport(),
         'PUT',
          '/testServer/echoBackBody',
          payload
      );

      waitForStreamEndToBeFiredOn(oboeBus);

      runs(function(){
         expect(streamedContentPassedTo(oboeBus)).toParseTo(payload);
         expect(oboeBus).toHaveGivenStreamEventsInCorrectOrder()
      });

   })

   it('can make a patch request',  function() {

      var payload = {'thisWill':'bePatched','andShould':'be','echoed':'back'};

      // in practice, since we're running on an internal network and this is a small file,
      // we'll probably only get one callback
      var oboeBus = fakePubSub(emittedEvents)
      streamingHttp(
         oboeBus,
         httpTransport(),
         'PATCH',
          '/testServer/echoBackBody',
          payload
      );

      waitForStreamEndToBeFiredOn(oboeBus);

      runs(function(){
         if( streamedContentPassedTo(oboeBus) == '' &&
             (Platform.isInternetExplorer || Platform.isPhantom) ) {
            console.warn( 'this user agent seems not to support giving content'
                          + ' back for of PATCH requests.'
                          + ' This happens on PhantomJS and IE < 9');
         } else {
            expect(streamedContentPassedTo(oboeBus)).toParseTo(payload);
            expect(oboeBus).toHaveGivenStreamEventsInCorrectOrder();
         }
      });

   })

   // this test is only activated for non-IE browsers and IE 10 or newer.
   // old and rubbish browsers buffer the xhr response meaning that this
   // will never pass. But for good browsers it is good to have an integration
   // test to confirm that we're getting it right.
   if( !Platform.isInternetExplorer || Platform.isInternetExplorer >= 10 ) {
      it('gives multiple callbacks when loading a streaming resource',  function() {

         var oboeBus = fakePubSub(emittedEvents)
         streamingHttp(
            oboeBus,
            httpTransport(),
            'GET',

            '/testServer/tenSlowNumbers',
             null // this is a get: no data to send
         );

         waitForStreamEndToBeFiredOn(oboeBus);

         runs(function(){

            // realistically, should have had 10 or 20, but this isn't deterministic so
            // 3 is enough to indicate the results didn't all arrive in one big blob.
            expect(oboeBus.callCount[STREAM_DATA]).toBeGreaterThan(3)
            expect(oboeBus).toHaveGivenStreamEventsInCorrectOrder()
         });
      })

      it('gives multiple callbacks when loading a gzipped streaming resource',  function() {

         var oboeBus = fakePubSub(emittedEvents)
         streamingHttp(
            oboeBus,
            httpTransport(),
            'GET',

            '/testServer/gzippedTwoHundredItems',
             null // this is a get: no data to send
         );

         waitForStreamEndToBeFiredOn(oboeBus);

         runs(function(){
            // some platforms can't help but not work here so warn but don't
            // fail the test:
            if( oboeBus.callCount[STREAM_DATA] == 1 &&
                  (Platform.isInternetExplorer || Platform.isPhantom) ) {
               console.warn('This user agent seems to give gzipped responses' +
                   'as a single event, not progressively. This happens on ' +
                   'PhantomJS and IE < 9');
            } else {
               expect(oboeBus.callCount[STREAM_DATA]).toBeGreaterThan(1);
            }

            expect(oboeBus).toHaveGivenStreamEventsInCorrectOrder();
         });
      })
   }

   it('does not call back with zero-length bites',  function() {

      // since this is a large file, even serving locally we're going to get multiple callbacks:
      var oboeBus = fakePubSub(emittedEvents)
      streamingHttp(
         oboeBus,
         httpTransport(),
         'GET',
         '/testServer/static/json/oneHundredRecords.json',
         null // this is a GET: no data to send
      );

      waitForStreamEndToBeFiredOn(oboeBus)

      runs(function(){

         var dripsReceived = oboeBus.eventTypesEmitted[STREAM_DATA].map(function( args ){
            return args[0];
         });

         expect(dripsReceived.length).toBeGreaterThan(0);

         dripsReceived.forEach(function(drip) {
            expect(drip.length).not.toEqual(0);
         });

      })
   })

   function waitForStreamEndToBeFiredOn(eventBus){
      waitsFor(function(){

         return !!eventBus(STREAM_END).emit.calls.length;

      }, 'streaming xhr to complete', ASYNC_TEST_TIMEOUT);
   }

   function streamedContentPassedTo(eventBus){

      return eventBus.eventTypesEmitted[STREAM_DATA].map(function(args){
         return args[0];
      }).join('');
   }

   beforeEach(function(){

      function prettyPrintEvent(event){

         switch(event) {
            case     HTTP_START:  return 'start';
            case     STREAM_DATA: return 'data';
            case     STREAM_END:  return 'end';
            default: return 'unknown(' + event + ')'
         }
      }

      this.addMatchers({
         toHaveGivenStreamEventsInCorrectOrder: function(){

            var eventNames = this.actual.eventNames;

            this.message = function(){
               return 'events not in correct order. We have: ' +
                        JSON.stringify(
                           eventNames.map(prettyPrintEvent)
                        )
            };

            return   eventNames[0] === HTTP_START
                  && eventNames[1] === STREAM_DATA
                  && eventNames[eventNames.length-1] === STREAM_END;
         },

         toParseTo:function( expectedObj ){

            var actual = this.actual;
            var normalisedActual;

            if( !actual ) {
               this.message = function(){
                  return 'no content has been received';
               }
               return false;
            }

            try{
               normalisedActual = JSON.stringify( JSON.parse(actual) );
            }catch(e){

               this.message = function(){

                  return "Expected to be able to parse the found " +
                      "content as json '" + actual + "' but it " +
                      "could not be parsed";
               }

               return false;
            }

            this.message = function(){
               return "The found json parsed but did not match " + JSON.stringify(expectedObj) +
                        " because found " + this.actual;
            }

            return (normalisedActual === JSON.stringify(expectedObj));
         }
      });

   });

   function headerObjectContaining(key, val) {
      // some browsers lowercase the header keys. Compare upper and lower
      // case versions:

      return {
         jasmineMatches: function(obj){
            return obj[key] == val || obj[key.toLowerCase()] == val;
         }
      }
   }

});
<|endoftext|>


<commit_before>window.imagine=function(nodes,callback){
	// Verify
	if(typeof callback!='function'){
		throw "A function is expected as callback argument";
	}
	// Normalize
	if(typeof nodes.length=='undefined'){
		nodes=[nodes];
	}
	// Prepare
	var i,j,image,src,
		loading=nodes.length,
		onload=function(){
			if(!--loading){
				callback.call(nodes);
			}
		},
		onerror=function(src){
			return function(){
				--loading;
				console.warn("An error has occured while loading '"+src+"'");
			};
		};
	// Register callbacks
	for(i=0,j=nodes.length;i<j;++i){
		image=new Image();
		image.src=nodes[i].src;
		if(image.complete===true){
			onload();
		}
		else{
			image.onload=onload;
			image.onerror=onerror(nodes[i].src);
		}
	}
};				<commit_msg>Add AMD support<commit_after>/*
	Imagine, an image loader with promises

	Author
		Aurélien Delogu (dev@dreamysource.fr)
*/

;(function(context,name,definition){
	if(typeof module!='undefined' && module.exports){
		module.exports=definition();
	}
	else if(typeof define=='function' && define.amd){
		define(definition);
	}
	else{
		context[name]=definition();
	}
}(this,'imagine',function(nodes,callback){

	// Verify
	if(typeof callback!='function'){
		throw "A function is expected as callback argument";
	}
	// Normalize
	if(typeof nodes.length=='undefined'){
		nodes=[nodes];
	}
	// Prepare
	var i,j,image,src,
		loading=nodes.length,
		onload=function(){
			if(!--loading){
				callback.call(nodes);
			}
		},
		onerror=function(src){
			return function(){
				--loading;
				console.warn("An error has occured while loading '"+src+"'");
			};
		};
	// Register callbacks
	for(i=0,j=nodes.length;i<j;++i){
		image=new Image();
		image.src=nodes[i].src;
		if(image.complete===true){
			onload();
		}
		else{
			image.onload=onload;
			image.onerror=onerror(nodes[i].src);
		}
	}

}));				<|endoftext|>


<commit_before>/**
 * XadillaX created at 2015-12-18 17:24:31 With ♥
 *
 * Copyright (c) 2015 Souche.com, all rights
 * reserved.
 */
"use strict";

var Consumer = require("../lib/consumer");

var consumer = new Consumer(
    "CID",
    "topic",
    "tag|*",
    "access_key",
    "secret_key");

consumer.on("message", function(message, ack) {
    console.log(message);

    setTimeout(function() {
        ack.done(Math.random() > 0.5);
    }, 1000);
});

console.log("Connecting to Aliyun ONS...");
consumer.init(function() {
    console.log("Initialized.");
    consumer.listen();
    console.log("Listened.");
});
<commit_msg>update example<commit_after>/**
 * XadillaX created at 2015-12-18 17:24:31 With ♥
 *
 * Copyright (c) 2015 Souche.com, all rights
 * reserved.
 */
"use strict";

var config = require("../test/_config");
var Consumer = require("../lib/consumer");

var consumer = new Consumer(
    config.consumerId,
    config.topic,
    "*",
    config.accessKey,
    config.secretKey);

consumer.on("message", function(message, ack) {
    console.log(message);

    setTimeout(function() {
        ack.done();
    }, 1000);
});

console.log("Connecting to Aliyun ONS...");
consumer.init(function() {
    console.log("Initialized.");
    consumer.listen();
    console.log("Listened.");
});
<|endoftext|>


<commit_before>(function () {
    'use strict';

    angular
        .module('fedramp.components')
        .component('gridSort', {
            templateUrl: 'src/templates/components/grid-sort.html',
            require: {
                gridController: '^grid'
            },
            controller: GridSort,
            controllerAs: 'controller',
            bindings: {
                name: '@',
                property: '@',
                caseSensitive: '@',
                header: '@',
                default: '@'
            }
        });

    GridSort.$inject = ['$log', '$parse', '$element'];

    /**
     * @constructor
     * @memberof Components
     * @example <grid-sort property="provider" header="Provider"></grid-sort>
     */
    function GridSort($log, $parse, $element){
        var self = this;
        self.activated = null;

        self.asc = true;

        self.$onInit = $onInit;
        self.sort = sort;
        self.highlight = highlight;
        self.toggleSort = toggleSort;
        self.clear = clear;

        function $onInit(){
            if(!self.name){
                throw 'Name must be specified for sort filter';
            }
            if(self.property){
                self.sortFunc = sortFunc;
            }
            restoreState();
            self.gridController.addSort(self);
        }

        /**
         * Stores the sort information to the grid state.
         *
         * @public
         * @memberof Components.GridSort
         */
        function saveState(){
            // Merge any existing parameters
            var existingParams =
                angular.extend(
                    self.gridController.state,{
                        'sort': (self.asc ? '' : '-') + self.name
                    });

            // Update url
            self.gridController.stateUpdate(existingParams);
        }

        /**
         * Restores the latest saved sort.
         *
         * @public
         * @memberof Components.GridSort
         */
        function restoreState(){
            var sortParam = self.gridController.state.sort;
            if(!sortParam){
                loadDefaultSort();
                return;
            }

            var m = sortParam.match(/(-)?(.*)/);
            if(m[2] !== self.name){
                return;
            }

            self.asc = (m[1] === undefined);
            self.activated = true;
            self.sort(self.asc);
        }

        /**
         * Loads a specified default sort. This is to ensure a grid applies a sort when first loaded.
         *
         * @public
         * @memberof Components.GridSort
         */
        function loadDefaultSort(){
            if(self.default){
                // Parse if default should be in asc/desc
                self.asc = self.default.split('-').reduce(function(p, c){
                    return false;
                });
                self.sort(self.asc);
            }
        }

        /**
         * Sorts a list of items in the grid controller by the property for this particular
         * grid sort.
         *
         * @public
         * @memberof Components.GridSort
         * @param {boolean} doAscending
         * Sort direction to use
         */
        function sort(doAscending){
            self.activated = angular.isDefined(doAscending);
            self.asc = doAscending;
            self.gridController.defaultSort = self;
            self.gridController.items.sort(self.sortFunc);
            $element.addClass('sort-selected');
            // Update state of all sorts
            self.gridController.updateSort();
            saveState();

        }

        /**
         * Toggles the sort. To maintain a consistent interaction, we always set the toggle to ascending
         * if the sort is not activated. This case would be hit when the user has clicked on the sort for the
         * first time or after another sort.
         *
         * @public
         * @memberof Components.GridSort
         */
        function toggleSort(){
            if(!self.activated){
                self.sort(true);
                return;
            }
            self.sort(!self.asc);
        }

        /**
         * Performs a generic sort.
         *
         * @public
         * @memberof Components.GridSort
         */
        function sortFunc(_a, _b) {
            // Enables to sort on multiple properties for a specific grid sort.
            var props = self.property.split(',');

            for(var x = 0; x < props.length; x++){
                var a = $parse(props[x])(_a);
                var b = $parse(props[x])(_b);

                // If we're dealing with numbers, delegate to number sort func
                if(angular.isNumber(a)){
                    return numberSortFunc(a, b);
                }

                // Normalize everything and make it all lowercase for fair comparison
                a = a.toLowerCase();
                b = b.toLowerCase();

                if(a < b){
                    return self.asc ? -1 : 1;
                }
                if(a > b) {
                    return self.asc ? 1 : -1;
                }
            }
            return 0;
        }

        /**
         * Handles generic numerical sort.
         */
        function numberSortFunc(a, b){
            if(self.asc){
                return a - b;
            }
            return b - a;
        }

        /**
         * Determines whether to highlight sort selected option.
         */
        function highlight(asc){
            if(!self.activated){
                return false;
            }
            if(self !== self.gridController.defaultSort){
                return false;
            }
            if(self.asc === asc){
                return true;
            }
            return false;
        }

        /**
         * Clears the sorting.
         *
         * @public
         * @memberof Components.GridSort
         */
        function clear(){
            self.activated = false;
            $element.removeClass('sort-selected');
        }
    }

})();
<commit_msg>Fix where invalid property name produced no results on sorting<commit_after>(function () {
    'use strict';

    angular
        .module('fedramp.components')
        .component('gridSort', {
            templateUrl: 'src/templates/components/grid-sort.html',
            require: {
                gridController: '^grid'
            },
            controller: GridSort,
            controllerAs: 'controller',
            bindings: {
                name: '@',
                property: '@',
                caseSensitive: '@',
                header: '@',
                default: '@'
            }
        });

    GridSort.$inject = ['$log', '$parse', '$element'];

    /**
     * @constructor
     * @memberof Components
     * @example <grid-sort property="provider" header="Provider"></grid-sort>
     */
    function GridSort($log, $parse, $element){
        var self = this;
        self.activated = null;

        self.asc = true;

        self.$onInit = $onInit;
        self.sort = sort;
        self.highlight = highlight;
        self.toggleSort = toggleSort;
        self.clear = clear;

        function $onInit(){
            if(!self.name){
                throw 'Name must be specified for sort filter';
            }
            if(self.property){
                self.sortFunc = sortFunc;
            }
            restoreState();
            self.gridController.addSort(self);
            self.gridController.stateUpdate();
        }

        /**
         * Stores the sort information to the grid state.
         *
         * @public
         * @memberof Components.GridSort
         */
        function saveState(){
            // Merge any existing parameters
            var existingParams =
                angular.extend(
                    self.gridController.state,{
                        'sort': (self.asc ? '' : '-') + self.name
                    });

            // Update url
            self.gridController.stateUpdate(existingParams);
        }

        /**
         * Restores the latest saved sort.
         *
         * @public
         * @memberof Components.GridSort
         */
        function restoreState(){
            var sortParam = self.gridController.state.sort;
            if(!sortParam){
                loadDefaultSort();
                return;
            }

            var m = sortParam.match(/(-)?(.*)/);
            if(m[2] !== self.name){
                return;
            }

            self.asc = (m[1] === undefined);
            self.activated = true;
            self.sort(self.asc);
        }

        /**
         * Loads a specified default sort. This is to ensure a grid applies a sort when first loaded.
         *
         * @public
         * @memberof Components.GridSort
         */
        function loadDefaultSort(){
            if(self.default){
                // Parse if default should be in asc/desc
                self.asc = self.default.split('-').reduce(function(p, c){
                    return false;
                });
                self.sort(self.asc);
            }
        }

        /**
         * Sorts a list of items in the grid controller by the property for this particular
         * grid sort.
         *
         * @public
         * @memberof Components.GridSort
         * @param {boolean} doAscending
         * Sort direction to use
         */
        function sort(doAscending){
            self.activated = angular.isDefined(doAscending);
            self.asc = doAscending;
            self.gridController.defaultSort = self;
            self.gridController.items.sort(self.sortFunc);
            $element.addClass('sort-selected');
            // Update state of all sorts
            self.gridController.updateSort();
            saveState();

        }

        /**
         * Toggles the sort. To maintain a consistent interaction, we always set the toggle to ascending
         * if the sort is not activated. This case would be hit when the user has clicked on the sort for the
         * first time or after another sort.
         *
         * @public
         * @memberof Components.GridSort
         */
        function toggleSort(){
            if(!self.activated){
                self.sort(true);
                return;
            }
            self.sort(!self.asc);
        }

        /**
         * Performs a generic sort.
         *
         * @public
         * @memberof Components.GridSort
         */
        function sortFunc(_a, _b) {
            // Enables to sort on multiple properties for a specific grid sort.
            var props = self.property.split(',');

            for(var x = 0; x < props.length; x++){
                var a = $parse(props[x])(_a);
                var b = $parse(props[x])(_b);

                // If we're dealing with numbers, delegate to number sort func
                if(angular.isNumber(a)){
                    return numberSortFunc(a, b);
                }

                // Normalize everything and make it all lowercase for fair comparison
                a = a.toLowerCase();
                b = b.toLowerCase();

                if(a < b){
                    return self.asc ? -1 : 1;
                }
                if(a > b) {
                    return self.asc ? 1 : -1;
                }
            }
            return 0;
        }

        /**
         * Handles generic numerical sort.
         */
        function numberSortFunc(a, b){
            if(self.asc){
                return a - b;
            }
            return b - a;
        }

        /**
         * Determines whether to highlight sort selected option.
         */
        function highlight(asc){
            if(!self.activated){
                return false;
            }
            if(self !== self.gridController.defaultSort){
                return false;
            }
            if(self.asc === asc){
                return true;
            }
            return false;
        }

        /**
         * Clears the sorting.
         *
         * @public
         * @memberof Components.GridSort
         */
        function clear(){
            self.activated = false;
            $element.removeClass('sort-selected');
        }
    }

})();
<|endoftext|>


<commit_before>function testCaseButtons(context) {
    $(context).find("button").click(
        function(event) {
            event.preventDefault();
            event.stopPropagation();
            var button = $(this);
            var testcase = button.closest("details.test").addClass('loading');
            var container = button.closest("div.form");
            var data = {
                action: button.attr("data-action")
            };
            var inputs = container.find("input");
            var post = true;
            container.find("textarea").add(inputs).each(
                function() {
                    var val = $(this).val();
                    if (val) {
                        data[$(this).attr("name")] = val;
                    } else {
                        $(this).siblings("ul.errorlist").remove();
                        $(this).before(
                            "

" +
                                "This field is required." +
                                "

"
                        );
                        post = false;
                    }
                }
            );
            if ( post ) {
                $.post(
                    testcase.attr("data-action-url"),
                    data,
                    function(data) {
                        var id = testcase.attr("id");
                        testcase.replaceWith(data);
                        var newCase = $("#" + id);
                        summaryDetails(newCase);
                        testCaseButtons(newCase);
                        $('.loadingCSS').detach();
                    });
            }
            function addLoadingCSS() {
                var vertHeight = (parseInt(testcase.css('height')) - parseInt(testcase.css('line-height'))) / 2 + 'px';
                var style = '';
                $('head').append(style);
            }
            addLoadingCSS();
        });
}

function autoFocus(trigger) {
    $(trigger).click(function() {
        if ($(this).parent().hasClass('open')) {
            $(this).parent().find('textarea').focus();
        }
    });
}

$(function() {
    autoFocus('details.stepfail > summary');
    autoFocus('details.testinvalid > summary');
    testCaseButtons("details.test");
    $("div[role=main]").ajaxError(
        function(event, request, settings) {
            $(this).prepend(
                '' + request.responseText + ''
            );
            $('.loadingCSS').detach();
        });
});
<commit_msg>Remove loading class from all elements on Ajax error.<commit_after>function testCaseButtons(context) {
    $(context).find("button").click(
        function(event) {
            event.preventDefault();
            event.stopPropagation();
            var button = $(this);
            var testcase = button.closest("details.test").addClass('loading');
            var container = button.closest("div.form");
            var data = {
                action: button.attr("data-action")
            };
            var inputs = container.find("input");
            var post = true;
            container.find("textarea").add(inputs).each(
                function() {
                    var val = $(this).val();
                    if (val) {
                        data[$(this).attr("name")] = val;
                    } else {
                        $(this).siblings("ul.errorlist").remove();
                        $(this).before(
                            "

" +
                                "This field is required." +
                                "

"
                        );
                        post = false;
                    }
                }
            );
            if ( post ) {
                $.post(
                    testcase.attr("data-action-url"),
                    data,
                    function(data) {
                        var id = testcase.attr("id");
                        testcase.replaceWith(data);
                        var newCase = $("#" + id);
                        summaryDetails(newCase);
                        testCaseButtons(newCase);
                        $('.loadingCSS').detach();
                    });
            }
            function addLoadingCSS() {
                var vertHeight = (parseInt(testcase.css('height')) - parseInt(testcase.css('line-height'))) / 2 + 'px';
                var style = '';
                $('head').append(style);
            }
            addLoadingCSS();
        });
}

function autoFocus(trigger) {
    $(trigger).click(function() {
        if ($(this).parent().hasClass('open')) {
            $(this).parent().find('textarea').focus();
        }
    });
}

$(function() {
    autoFocus('details.stepfail > summary');
    autoFocus('details.testinvalid > summary');
    testCaseButtons("details.test");
    $("div[role=main]").ajaxError(
        function(event, request, settings) {
            $(this).prepend(
                '' + request.responseText + ''
            );
            $('.loadingCSS').detach();
            $('.loading').removeClass("loading");
        });
});
<|endoftext|>


<commit_before>import React from 'react';

class features extends React.Component {
    render() {
        return (

Discover SlideWiki

>SlideWiki's goal is to revolutionise how educational materials can be authored, shared and reused. By enabling authors and students to create and share slide decks as HTML in an open platform, communities around the world can benefit from materials created by world-leading educators on a wide range of topics.

Create online slide decks

Create a new deck or import existing slides from PowerPoint (*.pptx) or OpenDocument Presentation (*.odp) files. Your imported slides will be converted into HTML to allow you to continue to edit and add new content.

SlideWiki's editor offers many formatting tools, including being able to add images, videos, equations and code snippet.

Reusable educational content

SlideWiki is built on the Open Educational Resources (OER) ethos and all content is published under Creative Commons licenses. This means you can reuse and repurpose content from SlideWiki decks. SlideWiki allows you to create your own slides based on decks that have been published on SlideWiki by:

Creating a copy of a deck

Use the Fork feature to create your own copy of an existing deck.

Appending slides and decks to your deck

Add slides from other decks using the Append feature. Or Append a deck to embed a set of slides as a sub-deck.

Translating a deck (coming soon)

Localise slides and decks by translating it into another language.

Collaborative content authoring

SlideWiki allows authors and students to collaborate. Through managing editing rights, you can enable colleagues to edit and add to your decks. Comments and Questions (coming soon) allow students and readers to interact with your decks.

Collaborate to improve your decks

Use Groups to allow colleagues, peers and associates to collaborate with editing and enhancing your deck.

Review and revert changes within slides and decks

A sophisticated revisioning model enables you and your co-editors to review and revert changes to slides and decks.

Like decks and slides

Encourage authors and students to see new content by liking useful decks and slides.

Presentation mode

Use the Presentation mode to view a deck as a slideshow. Includes a timer and speaker notes' view.

Supporting Knowledge Communities

Through a range of interactive and open tools, SlideWiki aims to nurture knowledge communities around the world. Our goal is to significantly increase content available to a world-wide audience. By involve peer-educators in improving and maintaining the quality and attractiveness of your e-learning content SlideWiki can give you a platform to support knowledge communities. With SlideWiki we aim to dramatically improve the efficiency and effectiveness of the collaborative creation of rich learning material for online and offline use.

Share decks via social media or email.

Add Comments to decks and slides to interact with other learners.

Download decks in PDF, ePub or SCROM format.

To find out more about how to use SlideWiki and its many features, view our help file deck.

        );
    }
}

export default features;
<commit_msg>new branch. fixed lint error<commit_after>import React from 'react';

class features extends React.Component {
    render() {
        return (

Discover SlideWiki

>SlideWiki's goal is to revolutionise how educational materials can be authored, shared and reused. By enabling authors and students to create and share slide decks as HTML in an open platform, communities around the world can benefit from materials created by world-leading educators on a wide range of topics.

Create online slide decks

Create a new deck or import existing slides from PowerPoint (*.pptx) or OpenDocument Presentation (*.odp) files. Your imported slides will be converted into HTML to allow you to continue to edit and add new content.

SlideWiki's editor offers many formatting tools, including being able to add images, videos, equations and code snippet.

Reusable educational content

SlideWiki is built on the Open Educational Resources (OER) ethos and all content is published under Creative Commons licenses. This means you can reuse and repurpose content from SlideWiki decks. SlideWiki allows you to create your own slides based on decks that have been published on SlideWiki by:

Creating a copy of a deck

Use the Fork feature to create your own copy of an existing deck.

Appending slides and decks to your deck

Add slides from other decks using the Append feature. Or Append a deck to embed a set of slides as a sub-deck.

Translating a deck (coming soon)

Localise slides and decks by translating it into another language.

Collaborative content authoring

SlideWiki allows authors and students to collaborate. Through managing editing rights, you can enable colleagues to edit and add to your decks. Comments and Questions (coming soon) allow students and readers to interact with your decks.

Collaborate to improve your decks

Use Groups to allow colleagues, peers and associates to collaborate with editing and enhancing your deck.

Review and revert changes within slides and decks

A sophisticated revisioning model enables you and your co-editors to review and revert changes to slides and decks.

Like decks and slides

Encourage authors and students to see new content by liking useful decks and slides.

Presentation mode

Use the Presentation mode to view a deck as a slideshow. Includes a timer and speaker notes' view.

Supporting Knowledge Communities

Through a range of interactive and open tools, SlideWiki aims to nurture knowledge communities around the world. Our goal is to significantly increase content available to a world-wide audience. By involve peer-educators in improving and maintaining the quality and attractiveness of your e-learning content SlideWiki can give you a platform to support knowledge communities. With SlideWiki we aim to dramatically improve the efficiency and effectiveness of the collaborative creation of rich learning material for online and offline use.

Share decks via social media or email.

Add Comments to decks and slides to interact with other learners.

Download decks in PDF, ePub or SCROM format.

To find out more about how to use SlideWiki and its many features, view our help file deck.

        );
    }
}

export default features;
<|endoftext|>


<commit_before>/*jslint vars: true, plusplus: true, devel: true, nomen: true, regexp: true, indent: 4, maxerr: 50 */
/*global define */
define(function (require, exports) {
    "use strict";

    var Content = require("filesystem/impls/filer/lib/content");
    var Path = require("filesystem/impls/filer/BracketsFiler").Path;
    var BlobUtils = require("filesystem/impls/filer/BlobUtils");

    /**
     * Rewrite all url(...) references to blob URL Objects from the fs.
     */
    function CSSRewriter(path, css) {
        this.path = path;
        this.dir = Path.dirname(path);
        this.css = css;
    }

    CSSRewriter.prototype.urls = function() {
        var dir = this.dir;
        var css = this.css;
        var replacements = [];

        // Do a two stage pass of the css content, replacing all interesting url(...)
        // uses with the contents of files in the server root.
        // Thanks to Pomax for helping with this
        function aggregate(content) {
            var urls = [];
            var urlRegex = new RegExp('url\\([\\\'\\"]\\?([^\\\'\\"\\)]+)[\\\'\\"]\\?\\)', 'g');

            function fetch(input) {
                if(input.length === 0) {
                    return;
                }

                var filename = input.splice(0,1)[0];
                var path = Path.resolve(dir, filename);

                replacements.push(function(content) {
                    // Swap the filename with the blob url
                    var period = new RegExp('\\.', 'g');
                    var forwardSlash = new RegExp('\\/', 'g');
                    var filenameCleaned = filename.replace(period, '\\.').replace(forwardSlash, '\\/');
                    var regex = new RegExp(filenameCleaned, 'gm');
                    return content.replace(regex, BlobUtils.getUrl(path));
                });

                fetch(input);
            }

            function fetchFiles(list) {
                fetch(list);
            }

            content.replace(urlRegex, function(_, url) {
                if(!Content.isRelativeURL(url)) {
                    return;
                }
                urls.push(url);
            });

            fetchFiles(urls);
        }

        aggregate(css);

        replacements.forEach(function(replacement) {
            css = replacement(css);
        });

        return css;
    };

    function rewrite(path, css) {
        var rewriter = new CSSRewriter(path, css);
        return rewriter.urls();
    }

    exports.rewrite = rewrite;
});
<commit_msg>Fix CSSRewriter regex to not escape ?<commit_after>/*jslint vars: true, plusplus: true, devel: true, nomen: true, regexp: true, indent: 4, maxerr: 50 */
/*global define */
define(function (require, exports) {
    "use strict";

    var Content = require("filesystem/impls/filer/lib/content");
    var Path = require("filesystem/impls/filer/BracketsFiler").Path;
    var BlobUtils = require("filesystem/impls/filer/BlobUtils");

    /**
     * Rewrite all url(...) references to blob URL Objects from the fs.
     */
    function CSSRewriter(path, css) {
        this.path = path;
        this.dir = Path.dirname(path);
        this.css = css;
    }

    CSSRewriter.prototype.urls = function() {
        var dir = this.dir;
        var css = this.css;
        var replacements = [];

        // Do a two stage pass of the css content, replacing all interesting url(...)
        // uses with the contents of files in the server root.
        // Thanks to Pomax for helping with this
        function aggregate(content) {
            var urls = [];
            var urlRegex = new RegExp('url\\([\\\'\\"]?([^\\\'\\"\\)]+)[\\\'\\"]?\\)', 'g');

            function fetch(input) {
                if(input.length === 0) {
                    return;
                }

                var filename = input.splice(0,1)[0];
                var path = Path.resolve(dir, filename);

                replacements.push(function(content) {
                    // Swap the filename with the blob url
                    var period = new RegExp('\\.', 'g');
                    var forwardSlash = new RegExp('\\/', 'g');
                    var filenameCleaned = filename.replace(period, '\\.').replace(forwardSlash, '\\/');
                    var regex = new RegExp(filenameCleaned, 'gm');
                    return content.replace(regex, BlobUtils.getUrl(path));
                });

                fetch(input);
            }

            function fetchFiles(list) {
                fetch(list);
            }

            content.replace(urlRegex, function(_, url) {
                if(!Content.isRelativeURL(url)) {
                    return;
                }
                urls.push(url);
            });

            fetchFiles(urls);
        }

        aggregate(css);

        replacements.forEach(function(replacement) {
            css = replacement(css);
        });

        return css;
    };

    function rewrite(path, css) {
        var rewriter = new CSSRewriter(path, css);
        return rewriter.urls();
    }

    exports.rewrite = rewrite;
});
<|endoftext|>