<commit_before>for ( var key in foam.UNUSED ) { foam.lookup(key); }

foam.CLASS({
  package: 'foam.doc',
  name: 'AxiomInfo',
  ids: ['name'],

  properties: [
    {
      name: 'axiom',
      hidden: true
    },
    {
      name: 'cls',
      label: 'Source Class',
      tableCellView: function(o, e) {
        return foam.doc.LinkView.create({data: o.cls}, e.__subSubContext__);
      },
      tableCellFormatter: function(value, obj, axiom) {
        this.tag(foam.doc.LinkView, { data: value });
      }
    },
    {
      name: 'type',
      tableCellView: function(o, e) {
        return o.type ?
          foam.doc.LinkView.create({data: foam.doc.Link.create({path: o.type.id, label: o.type.name})}, e.__subSubContext__) :
          'anonymous';
      },
      tableCellFormatter: function(value, obj, axiom) {
        if ( value ) {
          this.tag(foam.doc.LinkView, { data: foam.doc.Link.create({ path: value.id, label: value.name }) });
          return;
        }
        this.add('anonymous');
      }
    },
    {
      name: 'name'
    }
  ]
});

foam.CLASS({
  package: 'foam.doc',
  name: 'ClassList',
  extends: 'foam.u2.View',

  requires: [
    'foam.doc.ClassLink'
  ],

  methods: [
    function initE() {
      this.SUPER();

      var self = this;

      this.add('(', this.data.length, ')').br();

      this.data.forEach(function(cls) {
        self.start(self.ClassLink, {data: cls, showPackage: true}).end().br();
      });
    }
  ]
});

foam.CLASS({
  package: 'foam.doc',
  name: 'ClassDocView',
  extends: 'foam.u2.View',

  requires: [
    'foam.doc.Link',
    'foam.doc.ClassLink',
    'foam.doc.AxiomInfo',
    'foam.u2.view.TableView',
    'foam.dao.ArrayDAO'
  ],

  properties: [
    {
      class: 'Boolean',
      name: 'showInherited',
      value: true
    }
  ],

  methods: [
    function initE() {
      this.SUPER();

      var data = this.data;

      this.add('CLASS: ', data.name, ' (', data.count_, ')').br();
      this.add('extends: ');
      var cls = data;
      for ( var i = 0 ; cls ; i++ ) {
        cls = this.lookup(cls.model_.extends, true);
        if ( i ) this.add(' : ');
        this.start(this.ClassLink, {data: cls}).end();
        if ( cls === foam.core.FObject ) break;
      }
      this.br();
      this.add(data.documentation);

      this.add('Show Inherited: ').start(this.SHOW_INHERITED, {data$: this.showInherited$}).end();

      this.add(this.slot(function (showInherited) {
        // TODO: hide 'Source Class' column if showInherited is false
        var axs = [];
        for ( var key in data.axiomMap_ ) {
          if ( showInherited || Object.hasOwnProperty.call(data.axiomMap_, key) ) {
            var a  = data.axiomMap_[key];
            var ai = foam.doc.AxiomInfo.create({
              axiom: a,
              type: a.cls_,
              cls: this.Link.create({
                path: a.sourceCls_.id,
                label: a.sourceCls_.name
              }),
              name: a.name
            });
            axs.push(ai);
          }
        }

        return this.TableView.create({
          of: this.AxiomInfo,
          data: this.ArrayDAO.create({array: axs})
        });
      }));
    }
  ]
});

foam.CLASS({
  package: 'foam.doc',
  name: 'Link',

  properties: [
    'path',
    'label'
  ]
});

foam.CLASS({
  package: 'foam.doc',
  name: 'LinkView',
  extends: 'foam.u2.View',

  imports: [ 'browserPath' ],

  methods: [
    function initE() {
      this.SUPER();

      this.setNodeName('a').
        on('click', this.click).
        attrs({href: this.data.path}).
        add(this.data.label);
    }
  ],

  listeners: [
    function click(e) {
      this.browserPath$.set(this.data.path);
      e.preventDefault();
    }
  ]
});

foam.CLASS({
  package: 'foam.doc',
  name: 'ClassLink',
  extends: 'foam.u2.View',

  imports: [ 'browserPath' ],

  properties: [
    {
      class: 'Class',
      name: 'data'
    },
    {
      class: 'Boolean',
      name: 'showPackage'
    }
  ],

  methods: [
    function initE() {
      this.SUPER();

      this.setNodeName('a').
        on('click', this.click).
        attrs({href: this.data.id}).
        add(this.showPackage ? this.data.id : this.data.name);
    }
  ],

  listeners: [
    function click(e) {
      this.browserPath$.set(this.data.id);
      e.preventDefault();
    }
  ]
});

foam.CLASS({
  package: 'foam.doc',
  name: 'DocBrowser',
  extends: 'foam.u2.Element',

  requires: [
    'foam.doc.ClassList',
    'foam.doc.ClassDocView'
  ],

  exports: [
    'as data',
    'path as browserPath'
  ],

  properties: [
    'path',
    {
      class: 'FObjectProperty',
      name: 'axiom'
    }
  ],

  methods: [
    function initE() {
      this.SUPER();

      this.add('Path: ', this.PATH).br().br();

      this.
        start('table').
          start('tr').
            start('td').
            add('Classes:').
              style({'vertical-align': 'top', background: '#f5f5ea' }).
              start(this.ClassList, {data: Object.values(foam.USED).sort(foam.core.Model.ID.compare)}).
            end().
            start('td').
              style({'vertical-align': 'top', background: '#f5f5ea' }).
              add(this.slot(function(path) {
                var o = foam.lookup(path, true);
                if ( ! o ) return '';
                return this.ClassDocView.create({data: o});
              })).
            end().
            start('td').
              add('Sub-Classes:').
              style({'vertical-align': 'top', background: '#f5f5ea' }).
              add(this.slot(function(path) {
                var o = foam.lookup(path, true);
                if ( ! o ) return '';
                return this.ClassList.create({data: Object.values(foam.USED).filter(function(cls) { return cls.model_.extends == path || 'foam.core.' + cls.model_.extends == path; }).sort(foam.core.Model.ID.compare)});
              })).
            end().
            start('td').
              add('Required-by:').
              style({'vertical-align': 'top', background: '#f5f5ea' }).
              add(this.slot(function(path) {
                var o = foam.lookup(path, true);
                if ( ! o ) return '';
                // TODO: this could be done more efficiently, and memoized
                return this.ClassList.create({data: Object.values(foam.USED).filter(function(cls) {
                  return cls.model_.requires && cls.model_.requires.map(function(r) { return r.path; }).includes(path); }).sort(foam.core.Model.ID.compare)});
              })).
            end().
            start('td').
              style({'vertical-align': 'top', background: '#f5f5ea' }).
              add(this.AXIOM).
            end().
          end().
        end();
    }
  ]
});

// foam.doc.ClassDocView.create({data: foam.core.Property}).write();

foam.doc.DocBrowser.create({path: 'foam.core.Property'}).write();
<commit_msg>DocBrowser displays currently hovered axiom.<commit_after>for ( var key in foam.UNUSED ) { foam.lookup(key); }

foam.CLASS({
  package: 'foam.doc',
  name: 'AxiomInfo',
  ids: ['name'],

  properties: [
    {
      name: 'axiom',
      hidden: true
    },
    {
      name: 'cls',
      label: 'Source Class',
      tableCellView: function(o, e) {
        return foam.doc.LinkView.create({data: o.cls}, e.__subSubContext__);
      },
      tableCellFormatter: function(value, obj, axiom) {
        this.tag(foam.doc.LinkView, { data: value });
      }
    },
    {
      name: 'type',
      tableCellView: function(o, e) {
        return o.type ?
          foam.doc.LinkView.create({data: foam.doc.Link.create({path: o.type.id, label: o.type.name})}, e.__subSubContext__) :
          'anonymous';
      },
      tableCellFormatter: function(value, obj, axiom) {
        if ( value ) {
          this.tag(foam.doc.LinkView, { data: foam.doc.Link.create({ path: value.id, label: value.name }) });
          return;
        }
        this.add('anonymous');
      }
    },
    {
      name: 'name'
    }
  ]
});

foam.CLASS({
  package: 'foam.doc',
  name: 'ClassList',
  extends: 'foam.u2.View',

  requires: [
    'foam.doc.ClassLink'
  ],

  methods: [
    function initE() {
      this.SUPER();

      var self = this;

      this.add('(', this.data.length, ')').br();

      this.data.forEach(function(cls) {
        self.start(self.ClassLink, {data: cls, showPackage: true}).end().br();
      });
    }
  ]
});

foam.CLASS({
  package: 'foam.doc',
  name: 'ClassDocView',
  extends: 'foam.u2.View',

  requires: [
    'foam.doc.Link',
    'foam.doc.ClassLink',
    'foam.doc.AxiomInfo',
    'foam.u2.view.TableView',
    'foam.dao.ArrayDAO'
  ],

  imports: [
    'selectedAxiom'
  ],

  properties: [
    {
      class: 'Boolean',
      name: 'showInherited',
      value: true
    }
  ],

  methods: [
    function initE() {
      this.SUPER();

      var data = this.data;

      this.add('CLASS: ', data.name, ' (', data.count_, ')').br();
      this.add('extends: ');
      var cls = data;
      for ( var i = 0 ; cls ; i++ ) {
        cls = this.lookup(cls.model_.extends, true);
        if ( i ) this.add(' : ');
        this.start(this.ClassLink, {data: cls}).end();
        if ( cls === foam.core.FObject ) break;
      }
      this.br();
      this.add(data.documentation);

      this.add('Show Inherited: ').start(this.SHOW_INHERITED, {data$: this.showInherited$}).end();

      this.add(this.slot(function (showInherited) {
        // TODO: hide 'Source Class' column if showInherited is false
        var axs = [];
        for ( var key in data.axiomMap_ ) {
          if ( showInherited || Object.hasOwnProperty.call(data.axiomMap_, key) ) {
            var a  = data.axiomMap_[key];
            var ai = foam.doc.AxiomInfo.create({
              axiom: a,
              type: a.cls_,
              cls: this.Link.create({
                path: a.sourceCls_.id,
                label: a.sourceCls_.name
              }),
              name: a.name
            });
            axs.push(ai);
          }
        }

        return this.TableView.create({
          of: this.AxiomInfo,
          data: this.ArrayDAO.create({array: axs}),
          hoverSelection$: this.selectedAxiom$
        });
      }));
    }
  ]
});

foam.CLASS({
  package: 'foam.doc',
  name: 'Link',

  properties: [
    'path',
    'label'
  ]
});

foam.CLASS({
  package: 'foam.doc',
  name: 'LinkView',
  extends: 'foam.u2.View',

  imports: [ 'browserPath' ],

  methods: [
    function initE() {
      this.SUPER();

      this.setNodeName('a').
        on('click', this.click).
        attrs({href: this.data.path}).
        add(this.data.label);
    }
  ],

  listeners: [
    function click(e) {
      this.browserPath$.set(this.data.path);
      e.preventDefault();
    }
  ]
});

foam.CLASS({
  package: 'foam.doc',
  name: 'ClassLink',
  extends: 'foam.u2.View',

  imports: [ 'browserPath' ],

  properties: [
    {
      class: 'Class',
      name: 'data'
    },
    {
      class: 'Boolean',
      name: 'showPackage'
    }
  ],

  methods: [
    function initE() {
      this.SUPER();

      this.setNodeName('a').
        on('click', this.click).
        attrs({href: this.data.id}).
        add(this.showPackage ? this.data.id : this.data.name);
    }
  ],

  listeners: [
    function click(e) {
      this.browserPath$.set(this.data.id);
      e.preventDefault();
    }
  ]
});

foam.CLASS({
  package: 'foam.doc',
  name: 'DocBrowser',
  extends: 'foam.u2.Element',

  requires: [
    'foam.doc.ClassList',
    'foam.doc.ClassDocView'
  ],

  exports: [
    'as data',
    'path as browserPath',
    'axiom as selectedAxiom'
  ],

  properties: [
    'path',
    {
      class: 'FObjectProperty',
      name: 'axiom',
      view: { class: 'foam.u2.DetailView' }
    }
  ],

  methods: [
    function initE() {
      this.SUPER();

      this.add('Path: ', this.PATH).br().br();

      this.
        start('table').
          start('tr').
            start('td').
            add('Classes:').
              style({'vertical-align': 'top', background: '#f5f5ea' }).
              start(this.ClassList, {data: Object.values(foam.USED).sort(foam.core.Model.ID.compare)}).
            end().
            start('td').
              style({'vertical-align': 'top', background: '#f5f5ea' }).
              add(this.slot(function(path) {
                var o = foam.lookup(path, true);
                if ( ! o ) return '';
                return this.ClassDocView.create({data: o});
              })).
            end().
            start('td').
              add('Sub-Classes:').
              style({'vertical-align': 'top', background: '#f5f5ea' }).
              add(this.slot(function(path) {
                var o = foam.lookup(path, true);
                if ( ! o ) return '';
                return this.ClassList.create({data: Object.values(foam.USED).filter(function(cls) { return cls.model_.extends == path || 'foam.core.' + cls.model_.extends == path; }).sort(foam.core.Model.ID.compare)});
              })).
            end().
            start('td').
              add('Required-by:').
              style({'vertical-align': 'top', background: '#f5f5ea' }).
              add(this.slot(function(path) {
                var o = foam.lookup(path, true);
                if ( ! o ) return '';
                // TODO: this could be done more efficiently, and memoized
                return this.ClassList.create({data: Object.values(foam.USED).filter(function(cls) {
                  return cls.model_.requires && cls.model_.requires.map(function(r) { return r.path; }).includes(path); }).sort(foam.core.Model.ID.compare)});
              })).
            end().
            start('td').
              style({'vertical-align': 'top', background: '#f5f5ea' }).
              add(this.slot(function (axiom) { return axiom && foam.u2.DetailView.create({data: axiom.axiom}); })).
            end().
          end().
        end();
    }
  ]
});

foam.doc.DocBrowser.create({path: 'foam.core.Property'}).write();
<|endoftext|>


<commit_before>/*global PDFJS:false*/
/*eslint-env browser*/
/*eslint-env es6*/

var CSS_UNITS = 96.0 / 72.0; //this is apparently a thing.
var xform = 'transform';
['','webkit', 'Moz', 'O', 'ms'].every(function (prefix) {
    var e = prefix + (prefix ? 'T':'t') +  'ransform';
    if (typeof document.body.style[e] !== 'undefined') {
        xform = e;
        return false;
    }
    return true;
});

/*
!function (w) {

    function getOutputScale(ctx) {
        var devicePixelRatio = window.devicePixelRatio || 1;
        var backingStoreRatio = ctx.webkitBackingStorePixelRatio ||
                                ctx.mozBackingStorePixelRatio ||
                                ctx.msBackingStorePixelRatio ||
                                ctx.oBackingStorePixelRatio ||
                                ctx.backingStorePixelRatio || 1;
        var pixelRatio = devicePixelRatio / backingStoreRatio;
        return {
            sx: pixelRatio,
            sy: pixelRatio,
            scaled: pixelRatio !== 1
        };
    }

    PDFJS.getDocument('1609.01714.pdf').then(function (pdf) {
        var pageDivs = [];
        function createPage(n) {
            if (n > pdf.numPages) {
                return;
            }
            var div = document.createElement('div');
            pageDivs.push(div);
            pdf.getPage(n).then(function (page) {
                var scale = 0.6;
                var viewport = page.getViewport(scale * CSS_UNITS);

                var canvas = document.createElement('canvas');
                var context = canvas.getContext('2d');

                var outputScale = getOutputScale(canvas);
                canvas.height = viewport.height * outputScale.sy;
                canvas.width = viewport.width * outputScale.sx;

                div.appendChild(canvas);
                page.render({
                    canvasContext: context,
                    viewport: viewport
                });
            });
            createPage(n + 1);
        }
        createPage(1);
        pageDivs.forEach(function (div) {
            document.body.appendChild(div);
        });
    });
} (window);
*/

function getOutputScale(ctx) {
    var canvas;
    if (ctx === undefined) {
        if (canvas === undefined) {
            canvas = document.createElement('canvas');
        }
        ctx = canvas.getContext('2d');
    }
    var devicePixelRatio = window.devicePixelRatio || 1;
    var backingStoreRatio = ctx.webkitBackingStorePixelRatio ||
                            ctx.mozBackingStorePixelRatio ||
                            ctx.msBackingStorePixelRatio ||
                            ctx.oBackingStorePixelRatio ||
                            ctx.backingStorePixelRatio || 1;
    var pixelRatio = devicePixelRatio / backingStoreRatio;
    return {
        sx: pixelRatio,
        sy: pixelRatio,
        scaled: pixelRatio !== 1
    };
}

window.pdfViewer = function pdfViewer(container, documentUri) {
    // todo:
    /// Creates a pdf viewer in the given container
    /// <param name="container" type="HTMLElement">The container to create the pdf viewer in.</param>
    'use strict';

    if (container === null) {
        throw 'can not create viewer in null container';
    }
    if (container === undefined) {
        throw 'can not create viewer in undefined container';
    }
    if (!(container instanceof HTMLElement)) {
        throw 'can not create viewer in container that is not HTMLElement';
    }
    /** @type HTMLElement */
    var _container = container;

    /** @type String */
    var _uri = documentUri;
    /** @type HTMLElement */
    var _inner;
    /** @type PDFPromise<PDFDocumentProxy> */
    var _loadingTask;
    /** @type PDFDocumentProxy */
    var _pdfDocument;

    var _pages = [];
    /** @type {number} */
    var _pageCount;
    /** @type {number} */
    var _scale = defaultScale();
    /** @type {number} */
    var _page_gap = 10; //pixel space between pages

    var _resizeEventTriggered = false;

    initialiseContainers();
    setPdf(_uri);

    var _viewer = {
        position: function (value) {
            if (value === undefined) {
                return _container.scrollLeft;
            }
            _container.scrollLeft = value;
        },
    };
    return _viewer;

    function renderViewer() {
        _pages.forEach(function (p) {
            redrawPage(p);
        });
    }

    /**
     * @param {String} uri
     */
    function setPdf(uri) {
        _loadingTask = PDFJS.getDocument(uri);
        _loadingTask.then(pdfReady);
    }
    /**
     * @param {PDFDocumentProxy} pdf
     */
    function pdfReady(pdf) {
        _pdfDocument = pdf;
        _pageCount = pdf.numPages;
        addPageContainers();
        _pdfDocument.getDownloadInfo().then(pdfLoaded);
    }
    /**
     * @param {PDFDocumentProxy} pdf
     */
    function pdfLoaded() {
        //create pageViewObjects
        for (var n = 1; n <= _pageCount; ++n) {
            var pageView = {
                id: n,
                scale: _scale,
                rendered: false,
                loaded: false,
            };
            //todo: ? bind events
            _pages.push(pageView);
        }
        var pagePromises = [];
        _pages.forEach(function (pageView) {
            var pagePromise = _pdfDocument.getPage(pageView.id);
            pagePromises.push(pagePromise);
            var index = pageView.id - 1;
            /** @param {} page */
            pagePromise.then(function (page) {
                _pages[index].baseWidth = page.getViewport(1.0 * CSS_UNITS).width;
                _pages[index].defaultScale = defaultScale(_pages[index]);
                _pages[index].page = page;
                _pages[index].loaded = true;
            });
        });
        Promise.all(pagePromises).then(function () {
            _scale = _pages[0].defaultScale;
            renderViewer();
            registerEvents();
        });
    }

    function initialiseContainers() {
        _container.classList.add('pdfviewer-container');
        _inner = document.createElement('div');
        _inner.classList.add('pdfviewer-inner');
        _container.appendChild(_inner);
        //todo: add mini previews?
    }

    function addPageContainers() {
        for (var i = 0; i < _pageCount; ++i){
            var pageContainer = document.createElement('div');
            pageContainer.classList.add('pdfviewer-pagecontainer');
            pageContainer.classList.add('pdfviewer-loading');
            pageContainer.style.visibility = 'hidden';
            _inner.appendChild(pageContainer);
        }
    }

    function redrawPage(pageView) {
        var index = pageView.id - 1;
        var pageContainer = _inner.children[index];
        if (pageContainer === undefined) {
            throw 'can not redraw, not properly initialised';
        }
        var inView = pageInView(index);
        var rendered = pageView.rendered;
        var loaded = pageView.loaded;
        //draw page if it is in view and not currently rendered or has changed scale since last render.
        if (loaded && inView && (!rendered || _scale != pageView.scale)) {
            drawPage(pageView);
        }
        //clear a page which is not in view, but is currently rendered;
        if (!inView && rendered) {
            clearPage(pageView);
        }
    }

    function drawPage(pageView) {
        var index = pageView.id - 1;
        var pageContainer = _inner.children[index];

        var canvas = document.createElement('canvas');
        var outputScale = getOutputScale(canvas);
        var viewport = pageView.page.getViewport(_scale * CSS_UNITS * outputScale.sx);

        canvas.height = viewport.height;
        canvas.width = viewport.width;

        var context = canvas.getContext('2d');
        pageView.rendered = true;
        pageView.page.render({
            canvasContext: context,
            viewport: viewport
        }).then(function () {
            pageContainer.classList.remove('pdfview-loading');
            if (pageContainer.firstChild) {
                var hasChild = true;
            }
            pageContainer.appendChild(canvas);
            if (hasChild) {
                pageContainer.removeChild(pageContainer.firstChild);
            }
            pageContainer.style.visibility = 'visibile';
        });
    }

    function clearPage(pageView) {
        var index = pageView.id - 1;
        var pageContainer = _inner.children[index];
        while (pageContainer.firstChild) {
            pageContainer.removeChild(pageContainer.firstChild);
        }
        pageContainer.classList.add('pdfview-loading');
        pageView.rendered = false;
    }

    function pageInView(index) {
        var pageWidth = _pages[0].baseWidth * _scale * getOutputScale().sx;
        var viewerWidth = _container.clientWidth;
        var minIndex = Math.floor(_container.scrollLeft / (pageWidth + _page_gap)) - 1; //-1 to allow an extra page to be prerendered
        var maxIndex = Math.floor((_container.scrollLeft + viewerWidth) / (pageWidth + _page_gap)) + 1; //same for the + 1

        return index >= minIndex && index <= maxIndex;
    }

    function defaultScale(page) {
        ///Determine a reasonable default scale based on device
        if (page === undefined) {
            return 1;
        }
        return window.innerWidth / (page.baseWidth * getOutputScale().sx);
    }

    function registerEvents() {
        window.addEventListener('resize', onResize);
        _container.addEventListener('scroll', onScroll);
    }

    function onResize() {
        if (!_resizeEventTriggered) {
            window.requestAnimationFrame( function () {
                renderViewer();
                _resizeEventTriggered = false;
            });
        }
        _resizeEventTriggered = true;
    }

    function onScroll() {
        if (!_resizeEventTriggered) {
            window.requestAnimationFrame( function () {
                renderViewer();
                _resizeEventTriggered = false;
            });
        }
        _resizeEventTriggered = true;
    }
};<commit_msg>fix typo<commit_after>/*global PDFJS:false*/
/*eslint-env browser*/
/*eslint-env es6*/

var CSS_UNITS = 96.0 / 72.0; //this is apparently a thing.
var xform = 'transform';
['','webkit', 'Moz', 'O', 'ms'].every(function (prefix) {
    var e = prefix + (prefix ? 'T':'t') +  'ransform';
    if (typeof document.body.style[e] !== 'undefined') {
        xform = e;
        return false;
    }
    return true;
});

/*
!function (w) {

    function getOutputScale(ctx) {
        var devicePixelRatio = window.devicePixelRatio || 1;
        var backingStoreRatio = ctx.webkitBackingStorePixelRatio ||
                                ctx.mozBackingStorePixelRatio ||
                                ctx.msBackingStorePixelRatio ||
                                ctx.oBackingStorePixelRatio ||
                                ctx.backingStorePixelRatio || 1;
        var pixelRatio = devicePixelRatio / backingStoreRatio;
        return {
            sx: pixelRatio,
            sy: pixelRatio,
            scaled: pixelRatio !== 1
        };
    }

    PDFJS.getDocument('1609.01714.pdf').then(function (pdf) {
        var pageDivs = [];
        function createPage(n) {
            if (n > pdf.numPages) {
                return;
            }
            var div = document.createElement('div');
            pageDivs.push(div);
            pdf.getPage(n).then(function (page) {
                var scale = 0.6;
                var viewport = page.getViewport(scale * CSS_UNITS);

                var canvas = document.createElement('canvas');
                var context = canvas.getContext('2d');

                var outputScale = getOutputScale(canvas);
                canvas.height = viewport.height * outputScale.sy;
                canvas.width = viewport.width * outputScale.sx;

                div.appendChild(canvas);
                page.render({
                    canvasContext: context,
                    viewport: viewport
                });
            });
            createPage(n + 1);
        }
        createPage(1);
        pageDivs.forEach(function (div) {
            document.body.appendChild(div);
        });
    });
} (window);
*/

function getOutputScale(ctx) {
    var canvas;
    if (ctx === undefined) {
        if (canvas === undefined) {
            canvas = document.createElement('canvas');
        }
        ctx = canvas.getContext('2d');
    }
    var devicePixelRatio = window.devicePixelRatio || 1;
    var backingStoreRatio = ctx.webkitBackingStorePixelRatio ||
                            ctx.mozBackingStorePixelRatio ||
                            ctx.msBackingStorePixelRatio ||
                            ctx.oBackingStorePixelRatio ||
                            ctx.backingStorePixelRatio || 1;
    var pixelRatio = devicePixelRatio / backingStoreRatio;
    return {
        sx: pixelRatio,
        sy: pixelRatio,
        scaled: pixelRatio !== 1
    };
}

window.pdfViewer = function pdfViewer(container, documentUri) {
    // todo:
    /// Creates a pdf viewer in the given container
    /// <param name="container" type="HTMLElement">The container to create the pdf viewer in.</param>
    'use strict';

    if (container === null) {
        throw 'can not create viewer in null container';
    }
    if (container === undefined) {
        throw 'can not create viewer in undefined container';
    }
    if (!(container instanceof HTMLElement)) {
        throw 'can not create viewer in container that is not HTMLElement';
    }
    /** @type HTMLElement */
    var _container = container;

    /** @type String */
    var _uri = documentUri;
    /** @type HTMLElement */
    var _inner;
    /** @type PDFPromise<PDFDocumentProxy> */
    var _loadingTask;
    /** @type PDFDocumentProxy */
    var _pdfDocument;

    var _pages = [];
    /** @type {number} */
    var _pageCount;
    /** @type {number} */
    var _scale = defaultScale();
    /** @type {number} */
    var _page_gap = 10; //pixel space between pages

    var _resizeEventTriggered = false;

    initialiseContainers();
    setPdf(_uri);

    var _viewer = {
        position: function (value) {
            if (value === undefined) {
                return _container.scrollLeft;
            }
            _container.scrollLeft = value;
        },
    };
    return _viewer;

    function renderViewer() {
        _pages.forEach(function (p) {
            redrawPage(p);
        });
    }

    /**
     * @param {String} uri
     */
    function setPdf(uri) {
        _loadingTask = PDFJS.getDocument(uri);
        _loadingTask.then(pdfReady);
    }
    /**
     * @param {PDFDocumentProxy} pdf
     */
    function pdfReady(pdf) {
        _pdfDocument = pdf;
        _pageCount = pdf.numPages;
        addPageContainers();
        _pdfDocument.getDownloadInfo().then(pdfLoaded);
    }
    /**
     * @param {PDFDocumentProxy} pdf
     */
    function pdfLoaded() {
        //create pageViewObjects
        for (var n = 1; n <= _pageCount; ++n) {
            var pageView = {
                id: n,
                scale: _scale,
                rendered: false,
                loaded: false,
            };
            //todo: ? bind events
            _pages.push(pageView);
        }
        var pagePromises = [];
        _pages.forEach(function (pageView) {
            var pagePromise = _pdfDocument.getPage(pageView.id);
            pagePromises.push(pagePromise);
            var index = pageView.id - 1;
            /** @param {} page */
            pagePromise.then(function (page) {
                _pages[index].baseWidth = page.getViewport(1.0 * CSS_UNITS).width;
                _pages[index].defaultScale = defaultScale(_pages[index]);
                _pages[index].page = page;
                _pages[index].loaded = true;
            });
        });
        Promise.all(pagePromises).then(function () {
            _scale = _pages[0].defaultScale;
            renderViewer();
            registerEvents();
        });
    }

    function initialiseContainers() {
        _container.classList.add('pdfviewer-container');
        _inner = document.createElement('div');
        _inner.classList.add('pdfviewer-inner');
        _container.appendChild(_inner);
        //todo: add mini previews?
    }

    function addPageContainers() {
        for (var i = 0; i < _pageCount; ++i){
            var pageContainer = document.createElement('div');
            pageContainer.classList.add('pdfviewer-pagecontainer');
            pageContainer.classList.add('pdfviewer-loading');
            pageContainer.style.visibility = 'hidden';
            _inner.appendChild(pageContainer);
        }
    }

    function redrawPage(pageView) {
        var index = pageView.id - 1;
        var pageContainer = _inner.children[index];
        if (pageContainer === undefined) {
            throw 'can not redraw, not properly initialised';
        }
        var inView = pageInView(index);
        var rendered = pageView.rendered;
        var loaded = pageView.loaded;
        //draw page if it is in view and not currently rendered or has changed scale since last render.
        if (loaded && inView && (!rendered || _scale != pageView.scale)) {
            drawPage(pageView);
        }
        //clear a page which is not in view, but is currently rendered;
        if (!inView && rendered) {
            clearPage(pageView);
        }
    }

    function drawPage(pageView) {
        var index = pageView.id - 1;
        var pageContainer = _inner.children[index];

        var canvas = document.createElement('canvas');
        var outputScale = getOutputScale(canvas);
        var viewport = pageView.page.getViewport(_scale * CSS_UNITS * outputScale.sx);

        canvas.height = viewport.height;
        canvas.width = viewport.width;

        var context = canvas.getContext('2d');
        pageView.rendered = true;
        pageView.page.render({
            canvasContext: context,
            viewport: viewport
        }).then(function () {
            pageContainer.classList.remove('pdfview-loading');
            if (pageContainer.firstChild) {
                var hasChild = true;
            }
            pageContainer.appendChild(canvas);
            if (hasChild) {
                pageContainer.removeChild(pageContainer.firstChild);
            }
            pageContainer.style.visibility = 'visible';
        });
    }

    function clearPage(pageView) {
        var index = pageView.id - 1;
        var pageContainer = _inner.children[index];
        while (pageContainer.firstChild) {
            pageContainer.removeChild(pageContainer.firstChild);
        }
        pageContainer.classList.add('pdfview-loading');
        pageView.rendered = false;
    }

    function pageInView(index) {
        var pageWidth = _pages[0].baseWidth * _scale * getOutputScale().sx;
        var viewerWidth = _container.clientWidth;
        var minIndex = Math.floor(_container.scrollLeft / (pageWidth + _page_gap)) - 1; //-1 to allow an extra page to be prerendered
        var maxIndex = Math.floor((_container.scrollLeft + viewerWidth) / (pageWidth + _page_gap)) + 1; //same for the + 1

        return index >= minIndex && index <= maxIndex;
    }

    function defaultScale(page) {
        ///Determine a reasonable default scale based on device
        if (page === undefined) {
            return 1;
        }
        return window.innerWidth / (page.baseWidth * getOutputScale().sx);
    }

    function registerEvents() {
        window.addEventListener('resize', onResize);
        _container.addEventListener('scroll', onScroll);
    }

    function onResize() {
        if (!_resizeEventTriggered) {
            window.requestAnimationFrame( function () {
                renderViewer();
                _resizeEventTriggered = false;
            });
        }
        _resizeEventTriggered = true;
    }

    function onScroll() {
        if (!_resizeEventTriggered) {
            window.requestAnimationFrame( function () {
                renderViewer();
                _resizeEventTriggered = false;
            });
        }
        _resizeEventTriggered = true;
    }
};<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 * Copyright 2018 The FOAM Authors.  All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.u2',
  name: 'FoamTagLoader',

  documentation: 'Converts <foam> tags in document into Views.',

  imports: [ 'document', 'window', 'classloader' ],

  methods: [
    function init() {
      this.window.addEventListener('load', this.onLoad, false);
    },

    function findPropertyIC(cls, name) {
      var ps = cls.getAxiomsByClass(foam.core.Property);
      for ( var i = 0 ; i < ps.length ; i++ ) {
        if ( name === ps[i].name.toLowerCase() ) return ps[i];
      }
    },

    function loadTag(el) {
      var clsName = el.getAttribute('class');

      this.classloader.load(clsName).then(function(cls) {
        var id  = el.id;

        var view = cls.create(null, foam.__context__);

        if ( view.toE ) {
          view = view.toE({}, foam.__context__);
        } else if ( ! foam.u2.Element.isInstance(view) )  {
          view = foam.u2.DetailView.create({data: view, showActions: true});
        }

        for ( var j = 0 ; j < el.attributes.length ; j++ ) {
          var attr = el.attributes[j];
          var p    = this.findPropertyIC(view.cls_, attr.name);
          if ( p ) p.set(view, attr.value);
        }

        el.outerHTML = view.outerHTML;
        view.load();

        // Store view in global variable if named. Useful for testing.
        if ( id ) global[id] = view;

      }.bind(this), function(e) {
        console.error(e);
        console.error('Failed to load class: ', clsName);
      });
    }
  ],

  listeners: [
    function onLoad() {
      var els = Array.from(this.document.getElementsByTagName('foam'));
      this.window.removeEventListener('load', this.onLoad);

      // Install last to first to avoid messing up the 'els' list.
      els.forEach(this.loadTag.bind(this));
    }
  ]
});

foam.u2.FoamTagLoader.create();
<commit_msg>Add support for creating views from Promises in FoamTagLoader.<commit_after>/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 * Copyright 2018 The FOAM Authors.  All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.u2',
  name: 'FoamTagLoader',

  documentation: 'Converts <foam> tags in document into Views.',

  imports: [ 'document', 'window', 'classloader' ],

  methods: [
    function init() {
      this.window.addEventListener('load', this.onLoad, false);
    },

    function findPropertyIC(cls, name) {
      var ps = cls.getAxiomsByClass(foam.core.Property);
      for ( var i = 0 ; i < ps.length ; i++ ) {
        if ( name === ps[i].name.toLowerCase() ) return ps[i];
      }
    },

    function loadTag(el) {
      var clsName = el.getAttribute('class');

      this.classloader.load(clsName).then(function(cls) {
        var obj = cls.create(null, foam.__context__);

        if ( obj.promiseE ) {
          obj.promiseE().then(function(view) { this.installView(el, view); });
        } else if ( obj.toE ) {
          this.installView(el, obj.toE({}, foam.__context__));
        } else if ( ! foam.u2.Element.isInstance(view) )  {
          installView(el, foam.u2.DetailView.create({data: view, showActions: true}));
        }
      }.bind(this), function(e) {
        console.error(e);
        console.error('Failed to load class: ', clsName);
      });
    },

    function installView(el, view) {
      var id  = el.id;

      for ( var j = 0 ; j < el.attributes.length ; j++ ) {
        var attr = el.attributes[j];
        var p    = this.findPropertyIC(view.cls_, attr.name);
        if ( p ) p.set(view, attr.value);
      }

      el.outerHTML = view.outerHTML;
      view.load();

      // Store view in global variable if named. Useful for testing.
      if ( id ) global[id] = view;
    }
  ],

  listeners: [
    function onLoad() {
      var els = Array.from(this.document.getElementsByTagName('foam'));
      this.window.removeEventListener('load', this.onLoad);

      // Install last to first to avoid messing up the 'els' list.
      els.forEach(this.loadTag.bind(this));
    }
  ]
});

foam.u2.FoamTagLoader.create();
<|endoftext|>


<commit_before>// REACT COMPONENTS
import React from 'react';
import {
  Form,
  Radio,
  Checkbox,
  Header
} from 'semantic-ui-react';

// PROJECT COMPONENTS
import {
  FormPartsContainer,
  // MassiveToggle,
  FormHeading,
  IntervalColumnHeadings,
  CashFlowRow
} from './formHelpers';

// ========================================
// COMPONENTS
// ========================================

const Utilities = function ({ client, type, time, setClientProperty }) {

  let climate     = client[ time + 'HasClimateControl' ],
      electricity = client[ time + 'NonHeatElectricity' ],
      phone       = client[ time + 'Phone' ],
      fuelAssist  = client[ time + 'HasFuelAssistance' ];

  let setChecked = function ( evnt, inputProps ) {
    var obj = { ...inputProps, value: inputProps.checked };
    setClientProperty( evnt, obj );
  };  // End setChecked()

  let toBool = function ( evnt, inputProps ) {
    var val = inputProps.value === 'Yes',
        obj = { ...inputProps, value: val };
    setClientProperty( evnt, obj );
  };  // End toBool()

  return (
    <wrapper>
      Which of these utilities do you pay for?

      <Checkbox
        name={time + 'HasClimateControl'}
        label={'Heating or cooling (e.g. A/C during summer)'}
        checked={climate}
        onChange={setChecked}
      />

      <Checkbox
        name={time + 'NonHeatElectricity'}
        label={'Electricity for non-heating purposes'}
        checked={electricity}
        onChange={setChecked}
      />

      <Checkbox
        name={time + 'Phone'}
        label={'Telephone service'}
        checked={phone}
        onChange={setChecked}
      />

      Do you get Fuel Assistance?
      <Form.Field style={{display: 'inline-block', paddingRight: '1em'}}>
        <Radio
          name={time + 'HasFuelAssistance'}
          label={'Yes'} value={'Yes'}
          checked={fuelAssist}
          onChange={toBool}
        />
      </Form.Field>
      <Form.Field style={{display: 'inline-block', paddingRight: '1em'}}>
        <Radio
          name={time + 'HasFuelAssistance'}
          label={'No'} value={'No'}
          checked={!fuelAssist}
          onChange={toBool}
        />
      </Form.Field>
    </wrapper>

  );
};  // End Utilities(<>)

const ShelterDetails = function ({ client, type, time, setClientProperty }) {

  let shelter = client[ time + 'Shelter' ],
      sharedProps = {
        client: client, type: type, time: time,
        setClientProperty: setClientProperty
      };

  if ( client.hasHousing ) {
    return (
      <wrapper>
        <IntervalColumnHeadings type={ type }/>
        <CashFlowRow {...sharedProps} generic={'RentShare'}> Rent Share </CashFlowRow>
        <CashFlowRow {...sharedProps}
          generic={'ContractRent'}
          labeInfo={'The full amount the landlord would charge without a Section 8 voucher'}>
            Contract Rent
        </CashFlowRow>
        <Utilities {...sharedProps}/>
      </wrapper>
    );

  } else if ( shelter === 'homeless' ) {
    return null;

  } else if ( shelter === 'renter' ) {
    return (
      <wrapper>
        <IntervalColumnHeadings type={ type }/>
        <CashFlowRow {...sharedProps} generic={'Rent'}> Rent </CashFlowRow>
        <Utilities {...sharedProps}/>
      </wrapper>
    );

  } else if ( shelter === 'homeowner' ) {
    return (
      <wrapper>
        <IntervalColumnHeadings type={ type }/>
        <CashFlowRow {...sharedProps} generic={'Mortgage'}> Mortgage </CashFlowRow>
        <CashFlowRow {...sharedProps} generic={'HousingInsurance'}> Insurance Costs </CashFlowRow>
        <CashFlowRow {...sharedProps} generic={'PropertyTax'}> Property Tax </CashFlowRow>
        <Utilities {...sharedProps}/>
      </wrapper>
    );

  }  // end which expenses
};  // End ShelterDetails(<>)

const ShelterRadio = function ({ currentValue, label, time, setClientProperty }) {

  var value = label.toLowerCase();

  return (
    <Form.Field>
      <Radio
        name={time + 'Shelter'}
        label={label}
        value={value}
        checked={currentValue === value}
        onChange={setClientProperty}
      />
    </Form.Field>
  );

};  // End ShelterRadio(<>)

/** @todo description
*
* @function
* @param {object} props
* @property {object} props.__ - explanation
*
* @returns Component
*/
const Housing = function ({ client, type, time, setClientProperty }) {

  // We're using a bunch of radio buttons. Since `checked` is defined
  // in Radio components, `setClientProperty()` would store it, but we
  // want the value, so get rid of checked.
  /** Makes sure values are propagated to 'current' properties if needed */
  let ensureFuture = function ( evnt, inputProps ) {
    var obj = { ...inputProps, checked: null, value: inputProps.value, fillFuture: true };
    setClientProperty( evnt, obj );
  };

  let sharedProps = {
    client: client, type: type, time: time,
    setClientProperty: ensureFuture
  };

  return (
    <wrapper>

      <FormHeading>Shelter</FormHeading>

      { client.hasHousing
      ? null
      : <wrapper>

        What is your housing situation?
        <ShelterRadio
          currentValue={client[ time + 'Shelter' ]}
          label={'Homeless'}
          time={time}
          setClientProperty={ensureFuture}
        />
        <ShelterRadio
          currentValue={client[ time + 'Shelter' ]}
          label={'Renter'}
          time={time}
          setClientProperty={ensureFuture}
        />
        <ShelterRadio
          currentValue={client[ time + 'Shelter' ]}
          label={'Homeowner'}
          time={time}
          setClientProperty={ensureFuture}
        />

      </wrapper>}

      <ShelterDetails {...sharedProps}/>

    </wrapper>
  );

};  // End Housing()

/** @todo description
*
* @todo Discuss splitting into a sub-progress bar and breaking it up
* into individual form pages.
*
* @function
* @param {object} props
* @property {object} props.__ - explanation
*
* @returns Component
*/
const ExpensesFormContent = function ({ client, time, setClientProperty }) {

  let type        = 'expense',
      sharedProps = { client: client, type: type, time: time, setClientProperty: setClientProperty };

  /** @todo 1) Can client only enter amounts not covered by other programs
  * for childcare expenses? 2) Does money from those programs count as income?
  * Answers: 1) Yes. 2) Unkown.
  *
  * @todo Only show questions that are relevant to the client's slected programs
  */
  return (
    <wrapper className='field-aligner two-column'>

      { (client[ time + 'ChildrenUnder12' ] > 0)
        ? <wrapper>
          <FormHeading subheading = {'A "child" is a person 12 or younger. Don\'t include amounts that are paid for by other benefit programs.\n'}>
            Reasonable Unreimbursed Non-Medical Child(ren) Care</FormHeading>
          <IntervalColumnHeadings type={type}/>
          <CashFlowRow {...sharedProps} generic={'ChildDirectCareCosts'}> Direct care costs </CashFlowRow>
          <CashFlowRow {...sharedProps} generic={'ChildBeforeAndAfterSchoolCareCosts'}> Before- and after-school care </CashFlowRow>
          <CashFlowRow {...sharedProps} generic={'ChildTransportationCosts'}> Transportation costs </CashFlowRow>
          <CashFlowRow {...sharedProps} generic={'ChildOtherCareCosts'}> Other care </CashFlowRow>
          <CashFlowRow {...sharedProps} type={'income'} generic={'EarnedIncomeBecauseOfChildCare'}> Income made possible by child care expenses </CashFlowRow>
        </wrapper>
        : null
      }

      {/** Wrapper here or else margins get added here, but not other
      * places, making spacing hard to manage */}
      <wrapper>
        <FormHeading>Child Support</FormHeading>
        <IntervalColumnHeadings type={type}/>
        <CashFlowRow {...sharedProps} generic={'ChildSupportPaidOut'}> LEGALLY OBLIGATED Child support paid out </CashFlowRow>
      </wrapper>

      {/* Head or spouse can't be a dependent, so they don't count */}
      {/* With future version of form, don't show if there are only elderly,
        but not disabled, members. Also, show if there are people between
        > 12, but <= 18 */}
      { client[ time + 'DisabledOrElderlyMember' ]
        ? <wrapper>
          <FormHeading subheading = {'For the care of people who are older than 12, but are still dependents (those under 18 or disabled). Don\'t include amounts that are paid for by other benefit programs.\n'}>
            Dependent Care of Persons Over 12 Years of Age</FormHeading>
          <IntervalColumnHeadings type={type}/>
          <CashFlowRow {...sharedProps} generic={'AdultDirectCareCosts'}> Direct care costs </CashFlowRow>
          <CashFlowRow {...sharedProps} generic={'AdultTransportationCosts'}> Transportation costs </CashFlowRow>
          <CashFlowRow {...sharedProps} generic={'AdultOtherCareCosts'}> Other care </CashFlowRow>
        </wrapper>
        : null
      }

      { !client[ time + 'DisabledOrElderlyHeadOrSpouse' ] && !client[ time + 'DisabledOrElderlyMember' ]
        ? null
        : <wrapper>
          <FormHeading>Unreimbursed Disabled/Handicapped/Elderly Assistance</FormHeading>

Unreimbursed expenses to cover care attendants and auxiliary apparatus for any family member who is elderly or is a person with disabilities. Auxiliary apparatus are items such as wheelchairs, ramps, adaptations to vehicles, or special equipment to enable a blind person to read or type, but only if these items are directly related to permitting the disabled person or other family member to work.

Examples of eligible disability assistance expenses:

The payments made on a motorized wheelchair for the 42 year old son of the head of household enable the son to leave the house and go to work each day on his own. Prior to the purchase of the motorized wheelchair, the son was unable to make the commute to work. These payments are an eligible disability assistance expense.

Payments to a care attendant to stay with a disabled 16-year-old child allow the child’s mother to go to work every day. These payments are an eligible disability assistance allowance.

          <IntervalColumnHeadings type={type}/>
          <CashFlowRow {...sharedProps} generic={'DisabledAssistance'}> Disabled/Handicapped assistance </CashFlowRow>
          <CashFlowRow {...sharedProps} generic={'EarnedIncomeBecauseOfAdultCare'}> Income made possible by assistance expenses </CashFlowRow>
        </wrapper>
      }

        {/* These medical expenses don't count for Section 8 unless
          the disabled person is the head or spouse. From
          http://www.tacinc.org/media/58886/S8MS%20Full%20Book.pdf
          Appendix B, item (D) */}
        { client[ time + 'DisabledOrElderlyHeadOrSpouse' ] || (client.hasSnap && client[ time + 'DisabledOrElderlyMember' ])
          ? <wrapper>
          <FormHeading>Unreimbursed Medical Expenses</FormHeading>

Do not repeat anything you already listed in the section above. Examples of allowable medical expenses:

The orthodontist expenses for a child’s braces.

Services of doctors and health care professionals.

Services of health care facilities.

Medical insurance premiums.

Prescription/non-prescription medicines (prescribed by a physician).

Transportation to treatment (cab fare, bus fare, mileage).

Dental expenses, eyeglasses, hearing aids, batteries.

Live-in or periodic medical assistance.

Monthly payment on accumulated medical bills (regular monthly payments on a bill that was previously incurred).

          <IntervalColumnHeadings type={type}/>
          <CashFlowRow {...sharedProps} generic='DisabledOrElderlyMedicalCosts'> Disabled/Elderly medical expenses </CashFlowRow>
          <CashFlowRow {...sharedProps} generic='MembersMedicalCosts'> Medical expenses of other members </CashFlowRow>
        </wrapper>
        : null
      }

      <Housing client={client} time={time} type={type} setClientProperty={setClientProperty} />

      <FormHeading>Other</FormHeading>
      <CashFlowRow {...sharedProps} generic={'OtherExpenses'}> Other Expenses </CashFlowRow>

    </wrapper>
  );

};  // End ExpensesFormContent()

/**
* @todo SNAP: Does a medical assistant's payments count as a medical expense?
* (Answer: Yes. https://www.mass.gov/service-details/snap-verifications)
* @todo SNAP: Medical expense only matters if household has elder/disabled, but
* are they any medical expenses or only those of the disabled person? "Medical
* Expenses for Disabled or Elderly". Also, do they sometimes need to
* enter medical expenses even if they don't have an elderly or disabled
* household member?
*/

/** @todo description
*
* @function
* @param {object} props
* @property {object} props.__ - explanation
*
* @returns Component
*/
// `props` is a cloned version of the original props. References broken.
const CurrentExpensesStep = function ( props ) {

  return (
    <Form className = 'expense-form'>
      <FormPartsContainer
        title     = {'Current Household Expenses'}
        clarifier = {null}
        left      = {{name: 'Previous', func: props.previousStep}}
        right     = {{name: 'Next', func: props.nextStep}}
      >
        <ExpensesFormContent {...props} client={props.client} time={'current'} />
      </FormPartsContainer>
    </Form>
  );

};  // End CurrentExpensesStep()

export { CurrentExpensesStep };
<commit_msg>Converts 'Current Expenses' step to new household data<commit_after>// REACT COMPONENTS
import React from 'react';
import {
  Form,
  Radio,
  Checkbox,
  Header
} from 'semantic-ui-react';

// PROJECT COMPONENTS
import {
  FormPartsContainer,
  // MassiveToggle,
  FormHeading,
  IntervalColumnHeadings,
  CashFlowRow
} from './formHelpers';

// LOGIC
import {
  getEveryMember,
  isHeadOrSpouse,
  getDependentMembers,
  isDisabled,
  isUnder13,
} from '../utils/getMembers';

// ========================================
// COMPONENTS
// ========================================

const Utilities = function ({ client, type, time, setClientProperty }) {

  let climate     = client[ time + 'HasClimateControl' ],
      electricity = client[ time + 'NonHeatElectricity' ],
      phone       = client[ time + 'Phone' ],
      fuelAssist  = client[ time + 'HasFuelAssistance' ];

  let setChecked = function ( evnt, inputProps ) {
    var obj = { ...inputProps, value: inputProps.checked };
    setClientProperty( evnt, obj );
  };  // End setChecked()

  let toBool = function ( evnt, inputProps ) {
    var val = inputProps.value === 'Yes',
        obj = { ...inputProps, value: val };
    setClientProperty( evnt, obj );
  };  // End toBool()

  return (
    <wrapper>
      Which of these utilities do you pay for?

      <Checkbox
        name={time + 'HasClimateControl'}
        label={'Heating or cooling (e.g. A/C during summer)'}
        checked={climate}
        onChange={setChecked}
      />

      <Checkbox
        name={time + 'NonHeatElectricity'}
        label={'Electricity for non-heating purposes'}
        checked={electricity}
        onChange={setChecked}
      />

      <Checkbox
        name={time + 'Phone'}
        label={'Telephone service'}
        checked={phone}
        onChange={setChecked}
      />

      Do you get Fuel Assistance?
      <Form.Field style={{display: 'inline-block', paddingRight: '1em'}}>
        <Radio
          name={time + 'HasFuelAssistance'}
          label={'Yes'} value={'Yes'}
          checked={fuelAssist}
          onChange={toBool}
        />
      </Form.Field>
      <Form.Field style={{display: 'inline-block', paddingRight: '1em'}}>
        <Radio
          name={time + 'HasFuelAssistance'}
          label={'No'} value={'No'}
          checked={!fuelAssist}
          onChange={toBool}
        />
      </Form.Field>
    </wrapper>

  );
};  // End Utilities(<>)

const ShelterDetails = function ({ client, type, time, setClientProperty }) {

  let shelter = client[ time + 'Shelter' ],
      sharedProps = {
        client: client, type: type, time: time,
        setClientProperty: setClientProperty
      };

  if ( client.hasHousing ) {
    return (
      <wrapper>
        <IntervalColumnHeadings type={ type }/>
        <CashFlowRow {...sharedProps} generic={'RentShare'}> Rent Share </CashFlowRow>
        <CashFlowRow {...sharedProps}
          generic={'ContractRent'}
          labeInfo={'The full amount the landlord would charge without a Section 8 voucher'}>
            Contract Rent
        </CashFlowRow>
        <Utilities {...sharedProps}/>
      </wrapper>
    );

  } else if ( shelter === 'homeless' ) {
    return null;

  } else if ( shelter === 'renter' ) {
    return (
      <wrapper>
        <IntervalColumnHeadings type={ type }/>
        <CashFlowRow {...sharedProps} generic={'Rent'}> Rent </CashFlowRow>
        <Utilities {...sharedProps}/>
      </wrapper>
    );

  } else if ( shelter === 'homeowner' ) {
    return (
      <wrapper>
        <IntervalColumnHeadings type={ type }/>
        <CashFlowRow {...sharedProps} generic={'Mortgage'}> Mortgage </CashFlowRow>
        <CashFlowRow {...sharedProps} generic={'HousingInsurance'}> Insurance Costs </CashFlowRow>
        <CashFlowRow {...sharedProps} generic={'PropertyTax'}> Property Tax </CashFlowRow>
        <Utilities {...sharedProps}/>
      </wrapper>
    );

  }  // end which expenses
};  // End ShelterDetails(<>)

const ShelterRadio = function ({ currentValue, label, time, setClientProperty }) {

  var value = label.toLowerCase();

  return (
    <Form.Field>
      <Radio
        name={time + 'Shelter'}
        label={label}
        value={value}
        checked={currentValue === value}
        onChange={setClientProperty}
      />
    </Form.Field>
  );

};  // End ShelterRadio(<>)

/** @todo description
*
* @function
* @param {object} props
* @property {object} props.__ - explanation
*
* @returns Component
*/
const Housing = function ({ client, type, time, setClientProperty }) {

  // We're using a bunch of radio buttons. Since `checked` is defined
  // in Radio components, `setClientProperty()` would store it, but we
  // want the value, so get rid of checked.
  /** Makes sure values are propagated to 'current' properties if needed */
  let ensureFuture = function ( evnt, inputProps ) {
    var obj = { ...inputProps, checked: null, value: inputProps.value, fillFuture: true };
    setClientProperty( evnt, obj );
  };

  let sharedProps = {
    client: client, type: type, time: time,
    setClientProperty: ensureFuture
  };

  return (
    <wrapper>

      <FormHeading>Shelter</FormHeading>

      { client.hasHousing
      ? null
      : <wrapper>

        What is your housing situation?
        <ShelterRadio
          currentValue={client[ time + 'Shelter' ]}
          label={'Homeless'}
          time={time}
          setClientProperty={ensureFuture}
        />
        <ShelterRadio
          currentValue={client[ time + 'Shelter' ]}
          label={'Renter'}
          time={time}
          setClientProperty={ensureFuture}
        />
        <ShelterRadio
          currentValue={client[ time + 'Shelter' ]}
          label={'Homeowner'}
          time={time}
          setClientProperty={ensureFuture}
        />

      </wrapper>}

      <ShelterDetails {...sharedProps}/>

    </wrapper>
  );

};  // End Housing()

/** @todo description
*
* @todo Discuss splitting into a sub-progress bar and breaking it up
* into individual form pages.
*
* @function
* @param {object} props
* @property {object} props.__ - explanation
*
* @returns Component
*/
const ExpensesFormContent = function ({ client, time, setClientProperty }) {

  let type        = 'expense',
      sharedProps = { client: client, type: type, time: time, setClientProperty: setClientProperty },
      household   = client[ time + 'Household' ];

  var isOver12 = function ( member ) { return member.age > 12; };

  // Won't include head or spouse
  var allDependents = getDependentMembers( household ),
      under13       = getEveryMember( allDependents, isUnder13 ),
      // or under13 = getUnder13Members( allDependents ),
      over12        = getEveryMember( allDependents, isOver12 );

  // 'Elderly' here is using the lowest common denominator - SNAP standards
  var isElderlyOrDisabled = function ( member ) {
    return isDisabled( member ) || member.age >= 60;
  };
  var elderlyOrDisabled = getEveryMember( household, isElderlyOrDisabled ),
      elderlyOrDisabledHeadAndSpouse = getEveryMember( elderlyOrDisabled, isHeadOrSpouse );

  /**
  * @todo Does money from any programs count as income?
  * @todo Complete only show questions that are relevant to the client's slected programs
  */
  return (
    <wrapper className='field-aligner two-column'>

      { under13.length > 0
        ? <wrapper>
          <FormHeading subheading = {'A "child" is a person 12 or younger. Don\'t include amounts that are paid for by other benefit programs.\n'}>
            Reasonable Unreimbursed Non-Medical Child(ren) Care</FormHeading>
          <IntervalColumnHeadings type={type}/>
          <CashFlowRow {...sharedProps} generic={'ChildDirectCareCosts'}> Direct care costs </CashFlowRow>
          <CashFlowRow {...sharedProps} generic={'ChildBeforeAndAfterSchoolCareCosts'}> Before- and after-school care </CashFlowRow>
          <CashFlowRow {...sharedProps} generic={'ChildTransportationCosts'}> Transportation costs </CashFlowRow>
          <CashFlowRow {...sharedProps} generic={'ChildOtherCareCosts'}> Other care </CashFlowRow>
          <CashFlowRow {...sharedProps} type={'income'} generic={'EarnedIncomeBecauseOfChildCare'}> Income made possible by child care expenses </CashFlowRow>
        </wrapper>
        : null
      }

      {/** Wrapper here or else margins get added here, but not other
      * places, making spacing hard to manage */}
      <wrapper>
        <FormHeading>Child Support</FormHeading>
        <IntervalColumnHeadings type={type}/>
        <CashFlowRow {...sharedProps} generic={'ChildSupportPaidOut'}> LEGALLY OBLIGATED Child support paid out </CashFlowRow>
      </wrapper>

      {/* Head or spouse can't be a dependent, so they don't count */}
      {/* With future version of form, don't show if there are only elderly,
        but not disabled, members. Also, show if there are people between
        > 12, but <= 18 */}
      { over12.length > 0
        ? <wrapper>
          <FormHeading subheading = {'For the care of people who are older than 12, but are still dependents (those under 18 or disabled). Don\'t include amounts that are paid for by other benefit programs.\n'}>
            Dependent Care of Persons Over 12 Years of Age</FormHeading>
          <IntervalColumnHeadings type={type}/>
          <CashFlowRow {...sharedProps} generic={'AdultDirectCareCosts'}> Direct care costs </CashFlowRow>
          <CashFlowRow {...sharedProps} generic={'AdultTransportationCosts'}> Transportation costs </CashFlowRow>
          <CashFlowRow {...sharedProps} generic={'AdultOtherCareCosts'}> Other care </CashFlowRow>
        </wrapper>
        : null
      }

      { elderlyOrDisabled.length > 0
        ? <wrapper>
          <FormHeading>Unreimbursed Disabled/Handicapped/Elderly Assistance</FormHeading>

Unreimbursed expenses to cover care attendants and auxiliary apparatus for any family member who is elderly or is a person with disabilities. Auxiliary apparatus are items such as wheelchairs, ramps, adaptations to vehicles, or special equipment to enable a blind person to read or type, but only if these items are directly related to permitting the disabled person or other family member to work.

Examples of eligible disability assistance expenses:

The payments made on a motorized wheelchair for the 42 year old son of the head of household enable the son to leave the house and go to work each day on his own. Prior to the purchase of the motorized wheelchair, the son was unable to make the commute to work. These payments are an eligible disability assistance expense.

Payments to a care attendant to stay with a disabled 16-year-old child allow the child’s mother to go to work every day. These payments are an eligible disability assistance allowance.

          <IntervalColumnHeadings type={type}/>
          <CashFlowRow {...sharedProps} generic={'DisabledAssistance'}> Disabled/Handicapped assistance </CashFlowRow>
          <CashFlowRow {...sharedProps} generic={'EarnedIncomeBecauseOfAdultCare'}> Income made possible by assistance expenses </CashFlowRow>
        </wrapper>
        : null
      }

        {/* These medical expenses don't count for Section 8 unless
          the disabled person is the head or spouse. From
          http://www.tacinc.org/media/58886/S8MS%20Full%20Book.pdf
          Appendix B, item (D) */}
        { elderlyOrDisabledHeadAndSpouse.length > 0 || (client.hasSnap && elderlyOrDisabled.length > 0)
          ? <wrapper>
          <FormHeading>Unreimbursed Medical Expenses</FormHeading>

Do not repeat anything you already listed in the section above. Examples of allowable medical expenses:

The orthodontist expenses for a child’s braces.

Services of doctors and health care professionals.

Services of health care facilities.

Medical insurance premiums.

Prescription/non-prescription medicines (prescribed by a physician).

Transportation to treatment (cab fare, bus fare, mileage).

Dental expenses, eyeglasses, hearing aids, batteries.

Live-in or periodic medical assistance.

Monthly payment on accumulated medical bills (regular monthly payments on a bill that was previously incurred).

          <IntervalColumnHeadings type={type}/>
          <CashFlowRow {...sharedProps} generic='DisabledOrElderlyMedicalCosts'> Disabled/Elderly medical expenses </CashFlowRow>
          <CashFlowRow {...sharedProps} generic='MembersMedicalCosts'> Medical expenses of other members </CashFlowRow>
        </wrapper>
        : null
      }

      <Housing client={client} time={time} type={type} setClientProperty={setClientProperty} />

      <FormHeading>Other</FormHeading>
      <CashFlowRow {...sharedProps} generic={'OtherExpenses'}> Other Expenses </CashFlowRow>

    </wrapper>
  );

};  // End ExpensesFormContent()

/**
* @todo SNAP: Does a medical assistant's payments count as a medical expense?
* (Answer: Yes. https://www.mass.gov/service-details/snap-verifications)
* @todo SNAP: Medical expense only matters if household has elder/disabled, but
* are they any medical expenses or only those of the disabled person? "Medical
* Expenses for Disabled or Elderly". Also, do they sometimes need to
* enter medical expenses even if they don't have an elderly or disabled
* household member?
*/

/** @todo description
*
* @function
* @param {object} props
* @property {object} props.__ - explanation
*
* @returns Component
*/
// `props` is a cloned version of the original props. References broken.
const CurrentExpensesStep = function ( props ) {

  return (
    <Form className = 'expense-form'>
      <FormPartsContainer
        title     = {'Current Household Expenses'}
        clarifier = {null}
        left      = {{name: 'Previous', func: props.previousStep}}
        right     = {{name: 'Next', func: props.nextStep}}
      >
        <ExpensesFormContent {...props} client={props.client} time={'current'} />
      </FormPartsContainer>
    </Form>
  );

};  // End CurrentExpensesStep()

export { CurrentExpensesStep };
<|endoftext|>


<commit_before>import {TextSelection} from "prosemirror-state"

import {linkDialogTemplate} from "./templates"

import {Dialog} from "../../common"

export class LinkDialog {
    constructor(editor) {
        this.editor = editor
        this.link = ''
        this.defaultLink = 'https://'
        this.linkTitle = ''
        this.submitButtonText = gettext('Insert')
        this.dialog = false
        this.internalTargets = []
    }

    init() {
        this.checkLink()
        this.findInternalTargets()
        this.createDialog()
    }

    findInternalTargets() {

        let docs = [this.editor.view.state.doc, this.editor.mod.footnotes.fnEditor.view.state.doc],
        figures = {}

        docs.forEach(doc => doc.descendants(node => {
            if (node.type.name === 'heading') {
                this.internalTargets.push({
                    id: node.attrs.id,
                    text: node.textContent
                })
            }

            if (node.type.name === 'figure') {
                if (!figures[node.attrs.figureCategory]) {
                    figures[node.attrs.figureCategory] = 0
                }
                figures[node.attrs.figureCategory]++

                this.internalTargets.push({
                    id: node.attrs.id,
                    text: `${gettext(node.attrs.figureCategory)} ${figures[node.attrs.figureCategory]}: ${node.attrs.caption}`
                })
            }
        }))

    }

    // Check if there is an existing link at the selection. If this is the case
    // use its values in dialog.
    checkLink() {
        let state = this.editor.currentView.state,
            from = state.selection.from,
            linkMark = state.selection.$from.marks().find(
                mark => mark.type.name === 'link'
            )
        if (linkMark) {
            this.extendSelectionToMark(from, linkMark)
            this.submitButtonText = gettext('Update')
            this.linkTitle = linkMark.attrs.title ? linkMark.attrs.title : ''
            this.link = linkMark.attrs.href
        }
    }

    // Find the start and end of the link currently selected.
    extendSelectionToMark(pos, mark) {
        let view = this.editor.currentView,
            state = view.state,
            $pos = state.doc.resolve(pos),
            startIndex = $pos.index(),
            endIndex = $pos.indexAfter()

        while (startIndex > 0 && mark.isInSet($pos.parent.child(startIndex - 1).marks)) {
            startIndex--
        }
        while (endIndex < $pos.parent.childCount && mark.isInSet($pos.parent.child(endIndex).marks)) {
            endIndex++
        }
        let startPos = $pos.start(),
            endPos = startPos

        for (let i = 0; i < endIndex; i++) {
            let size = $pos.parent.child(i).nodeSize
            if (i < startIndex) {
                startPos += size
            }
            endPos += size
        }
        view.dispatch(
            state.tr.setSelection(TextSelection.create(state.doc, startPos, endPos))
        )
    }

    createDialog() {
        let buttons = []
        buttons.push({
            text: this.submitButtonText,
            class: 'fw-button fw-dark',
            click: () => {
                let linkType = this.dialog.find('input[name=link-type]:checked').val(),
                    newLink = '', linkTitle = ''
                if (linkType === 'internal') {
                    let targetId = this.dialog.find('select.internal-link-selector').val()
                    if (targetId) {
                        newLink = `#${targetId}`
                        linkTitle = this.internalTargets.find(target => target.id === targetId).text
                    }
                } else {
                    newLink = this.dialog.find('input.link').val()
                    linkTitle = this.dialog.find('input.link-title').val()
                }

                if ((new RegExp(/^\s*$/)).test(newLink) || newLink === this.defaultLink) {
                    // The link input is empty or hasn't been changed from the default value.
                    // Just close the dialog.
                    this.dialog.dialog('close')
                    this.editor.currentView.focus()
                    return
                }

                if ((new RegExp(/^\s*$/)).test(linkTitle)) {
                    // The link title is empty. Make it the same as the link itself.
                    linkTitle = newLink
                }

                this.dialog.dialog('close')
                let view = this.editor.currentView,
                    posFrom = view.state.selection.from,
                    posTo = view.state.selection.to,
                    markType = view.state.schema.marks.link.create({
                        href: newLink,
                        title: linkTitle
                    })
                // There is an empty selection. We insert the link title into the editor
                // and then add the link to that.
                if (posFrom===posTo) {
                    view.dispatch(view.state.tr.insertText(linkTitle, posFrom, posTo))
                    posTo = posFrom + linkTitle.length
                }
                view.dispatch(view.state.tr.addMark(
                    posFrom,
                    posTo,
                    markType
                ))
                view.focus()
                return
            }
        })

        buttons.push({
            type: 'cancel',
            click: () => {
                this.dialog.dialog('close')
                this.editor.currentView.focus()
            }
        })

        this.dialog = new Dialog({
            id: 'edit-link',
            title: gettext("Link"),
            body: linkDialogTemplate({
                linkTitle: this.linkTitle,
                link: this.link,
                defaultLink: this.defaultLink,
                internalTargets: this.internalTargets
            }),
            buttons,
            width: 836,
            height: 360,
            onClose: () => this.editor.currentView.focus()
        })

        this.dialog.open()

        if (this.internalTargets.length) {
            let externalEls = this.dialog.dialogEl.querySelectorAll('input.link, input.link-title'),
                internalEls = this.dialog.dialogEl.querySelectorAll('select.internal-link-selector'),
                externalSwitchers = this.dialog.dialogEl.querySelectorAll('input.link, input.link-title, label.link-external-label, input.link-external-check'),
                internalSwitchers = this.dialog.dialogEl.querySelectorAll('select.internal-link-selector, label.link-internal-label, input.link-internal-check'),
                radioInternal = this.dialog.dialogEl.querySelector('input.link-internal-check'),
                radioExternal = this.dialog.dialogEl.querySelector('input.link-external-check')

            if (this.link[0] === '#') {
                externalEls.forEach(el => el.classList.add("disabled"))
                radioInternal.checked = true
            } else {
                internalEls.forEach(el => el.classList.add("disabled"))
                radioExternal.checked = true
            }

            internalSwitchers.forEach(el => el.addEventListener('click', () => {
                externalEls.forEach(el => el.classList.add("disabled"))
                internalEls.forEach(el => el.classList.remove("disabled"))
                radioInternal.checked = true
            }))

            externalSwitchers.forEach(el => el.addEventListener('click', () => {
                internalEls.forEach(el => el.classList.add("disabled"))
                externalEls.forEach(el => el.classList.remove("disabled"))
                radioExternal.checked = true
            }))

        }
    }
}
<commit_msg>fix link dialog<commit_after>import {TextSelection} from "prosemirror-state"

import {linkDialogTemplate} from "./templates"

import {Dialog} from "../../common"

export class LinkDialog {
    constructor(editor) {
        this.editor = editor
        this.link = ''
        this.defaultLink = 'https://'
        this.linkTitle = ''
        this.submitButtonText = gettext('Insert')
        this.dialog = false
        this.internalTargets = []
    }

    init() {
        this.checkLink()
        this.findInternalTargets()
        this.createDialog()
    }

    findInternalTargets() {

        let docs = [this.editor.view.state.doc, this.editor.mod.footnotes.fnEditor.view.state.doc],
        figures = {}

        docs.forEach(doc => doc.descendants(node => {
            if (node.type.name === 'heading') {
                this.internalTargets.push({
                    id: node.attrs.id,
                    text: node.textContent
                })
            }

            if (node.type.name === 'figure') {
                if (!figures[node.attrs.figureCategory]) {
                    figures[node.attrs.figureCategory] = 0
                }
                figures[node.attrs.figureCategory]++

                this.internalTargets.push({
                    id: node.attrs.id,
                    text: `${gettext(node.attrs.figureCategory)} ${figures[node.attrs.figureCategory]}: ${node.attrs.caption}`
                })
            }
        }))

    }

    // Check if there is an existing link at the selection. If this is the case
    // use its values in dialog.
    checkLink() {
        let state = this.editor.currentView.state,
            from = state.selection.from,
            linkMark = state.selection.$from.marks().find(
                mark => mark.type.name === 'link'
            )
        if (linkMark) {
            this.extendSelectionToMark(from, linkMark)
            this.submitButtonText = gettext('Update')
            this.linkTitle = linkMark.attrs.title ? linkMark.attrs.title : ''
            this.link = linkMark.attrs.href
        }
    }

    // Find the start and end of the link currently selected.
    extendSelectionToMark(pos, mark) {
        let view = this.editor.currentView,
            state = view.state,
            $pos = state.doc.resolve(pos),
            startIndex = $pos.index(),
            endIndex = $pos.indexAfter()

        while (startIndex > 0 && mark.isInSet($pos.parent.child(startIndex - 1).marks)) {
            startIndex--
        }
        while (endIndex < $pos.parent.childCount && mark.isInSet($pos.parent.child(endIndex).marks)) {
            endIndex++
        }
        let startPos = $pos.start(),
            endPos = startPos

        for (let i = 0; i < endIndex; i++) {
            let size = $pos.parent.child(i).nodeSize
            if (i < startIndex) {
                startPos += size
            }
            endPos += size
        }
        view.dispatch(
            state.tr.setSelection(TextSelection.create(state.doc, startPos, endPos))
        )
    }

    createDialog() {
        let buttons = []
        buttons.push({
            text: this.submitButtonText,
            classes: 'fw-dark',
            click: () => {
                let linkType = this.dialog.dialogEl.querySelector('input[name=link-type]:checked').value,
                    newLink = '', linkTitle = ''
                if (linkType === 'internal') {
                    let targetId = this.dialog.dialogEl.querySelector('select.internal-link-selector').value
                    if (targetId) {
                        newLink = `#${targetId}`
                        linkTitle = this.internalTargets.find(target => target.id === targetId).text
                    }
                } else {
                    newLink = this.dialog.dialogEl.querySelector('input.link').value
                    linkTitle = this.dialog.dialogEl.querySelector('input.link-title').value
                }

                if ((new RegExp(/^\s*$/)).test(newLink) || newLink === this.defaultLink) {
                    // The link input is empty or hasn't been changed from the default value.
                    // Just close the dialog.
                    this.dialog.close()
                    this.editor.currentView.focus()
                    return
                }

                if ((new RegExp(/^\s*$/)).test(linkTitle)) {
                    // The link title is empty. Make it the same as the link itself.
                    linkTitle = newLink
                }

                this.dialog.close()
                let view = this.editor.currentView,
                    posFrom = view.state.selection.from,
                    posTo = view.state.selection.to,
                    markType = view.state.schema.marks.link.create({
                        href: newLink,
                        title: linkTitle
                    })
                // There is an empty selection. We insert the link title into the editor
                // and then add the link to that.
                if (posFrom===posTo) {
                    view.dispatch(view.state.tr.insertText(linkTitle, posFrom, posTo))
                    posTo = posFrom + linkTitle.length
                }
                view.dispatch(view.state.tr.addMark(
                    posFrom,
                    posTo,
                    markType
                ))
                view.focus()
                return
            }
        })

        buttons.push({
            type: 'cancel'
        })

        this.dialog = new Dialog({
            id: 'edit-link',
            title: gettext("Link"),
            body: linkDialogTemplate({
                linkTitle: this.linkTitle,
                link: this.link,
                defaultLink: this.defaultLink,
                internalTargets: this.internalTargets
            }),
            buttons,
            width: 836,
            height: 360,
            onClose: () => this.editor.currentView.focus()
        })

        this.dialog.open()

        if (this.internalTargets.length) {
            let externalEls = this.dialog.dialogEl.querySelectorAll('input.link, input.link-title'),
                internalEls = this.dialog.dialogEl.querySelectorAll('select.internal-link-selector'),
                externalSwitchers = this.dialog.dialogEl.querySelectorAll('input.link, input.link-title, label.link-external-label, input.link-external-check'),
                internalSwitchers = this.dialog.dialogEl.querySelectorAll('select.internal-link-selector, label.link-internal-label, input.link-internal-check'),
                radioInternal = this.dialog.dialogEl.querySelector('input.link-internal-check'),
                radioExternal = this.dialog.dialogEl.querySelector('input.link-external-check')

            if (this.link[0] === '#') {
                externalEls.forEach(el => el.classList.add("disabled"))
                radioInternal.checked = true
            } else {
                internalEls.forEach(el => el.classList.add("disabled"))
                radioExternal.checked = true
            }

            internalSwitchers.forEach(el => el.addEventListener('click', () => {
                externalEls.forEach(el => el.classList.add("disabled"))
                internalEls.forEach(el => el.classList.remove("disabled"))
                radioInternal.checked = true
            }))

            externalSwitchers.forEach(el => el.addEventListener('click', () => {
                internalEls.forEach(el => el.classList.add("disabled"))
                externalEls.forEach(el => el.classList.remove("disabled"))
                radioExternal.checked = true
            }))

        }
    }
}
<|endoftext|>


<commit_before>/**
 *    _____ __
 *   / ___// /_  _____
 *   \__ \/ / / / / _ \
 *  ___/ / / /_/ /  __/
 * /____/_/\__, /\___/
 *       /____/
 *       Copyright 2017 Slye Development Team. All Rights Reserved.
 *       Licence: MIT License
 */

var PrettyError = require('pretty-error');

exports.command = 'compile <file>';
exports.desc = 'Compile Esy file to JavaScript';
exports.builder = function (yargs) {
	yargs
		.option('out', {
			describe: 'Output file descriptor',
			type: 'string',
			alias: 'o'
		})
		.option('save', {
			describe: 'Save file in same directory',
			default: false,
			alias: 's'
		})
		.option('tree', {
			describe: 'Just print parsed code tree',
			default: false,
			alias: 't'
		});
		// .option('yes', {
		// 	describe: 'Replace file even if file names are the same, otherwise user should confirm rewrite',
		// 	default: false,
		// 	alias: 'y'
		// })
};
exports.handler = function (argv) {
	const   fs      = require('fs'),
			esy     = require('../loader')(argv);
			path    = require('path');
	var data    = fs.readFileSync(argv.file).toString();
	var tree    = esy.tree(data);
	var js;
	if(argv.tree){
		js  = JSON.stringify(tree, null, 4);
	}else {
		js  = esy.compile(tree);
	}
	if(argv.out){
		fs.writeFileSync(path.join(process.cwd(), argv.out), js)
	}else {
	 	if(argv.save){
	 		var file    = argv.file.substr(0, argv.file.lastIndexOf(".")) + '.esy.' + (argv.tree ? 'json' : 'js');
		    fs.writeFileSync(path.join(process.cwd(), file), js);
		    console.log(`Output saved to \`${file}\``);
	    }else {
		    console.log(js)
	    }
	}
};
<commit_msg>save file to what user specified via --save option<commit_after>/**
 *    _____ __
 *   / ___// /_  _____
 *   \__ \/ / / / / _ \
 *  ___/ / / /_/ /  __/
 * /____/_/\__, /\___/
 *       /____/
 *       Copyright 2017 Slye Development Team. All Rights Reserved.
 *       Licence: MIT License
 */

var PrettyError = require('pretty-error');

exports.command = 'compile <file>';
exports.desc = 'Compile Esy file to JavaScript';
exports.builder = function (yargs) {
	yargs
		.option('out', {
			describe: 'Output file descriptor',
			type: 'string',
			alias: 'o'
		})
		.option('save', {
			describe: 'Save file in same directory',
			default: false,
			alias: 's'
		})
		.option('tree', {
			describe: 'Just print parsed code tree',
			default: false,
			alias: 't'
		});
		// .option('yes', {
		// 	describe: 'Replace file even if file names are the same, otherwise user should confirm rewrite',
		// 	default: false,
		// 	alias: 'y'
		// })
};
exports.handler = function (argv) {
	const   fs      = require('fs'),
			esy     = require('../loader')(argv);
			path    = require('path');
	var data    = fs.readFileSync(argv.file).toString();
	var tree    = esy.tree(data);
	var js;
	if(argv.tree){
		js  = JSON.stringify(tree, null, 4);
	}else {
		js  = esy.compile(tree);
	}
	if(argv.out){
		fs.writeFileSync(path.join(process.cwd(), argv.out), js)
	}else {
	 	if(argv.save){
		    var file = path.join(process.cwd(), argv.file.substr(0, argv.file.lastIndexOf(".")) + '.esy.' + (argv.tree ? 'json' : 'js'));
		    if (typeof argv.save == 'string')
			    file = argv.save;
		    fs.writeFileSync(file, js);
		    console.log(`Output saved to \`${file}\``);
	    }else {
		    console.log(js)
	    }
	}
};
<|endoftext|>


<commit_before>import figureExtension from "./figure"
import asyncPhotoUpload from "./photoAjax"

require('../css/hjlog.scss');
require('script!showdown');
require('script!jquery');
require('script!./highlight');

// Markdown rendering
const postBody = document.getElementsByClassName("markdown")[0];
if (postBody) {
  figureExtension(showdown);
  const md = $(".markdown").text();
  const converter = new showdown.Converter({
    'extensions': ['figure'],
    'strikethrough': true,
    'tables': true,
    'noHeaderId': true});
  const html = converter.makeHtml(md);

  postBody.innerHTML = converter.makeHtml(md);
  postBody.style.display = "block";

  const dimmer = document.getElementsByClassName("dimmer")[0];
  dimmer.style.display = "none";
}

// Syntax highlighting
hljs.initHighlightingOnLoad();

// Responsive navbar
const trigger = document.getElementsByClassName('trigger')[0];
trigger.addEventListener("click", () => {
  const nav = document.getElementsByTagName('nav')[0];

  if (nav.style.display === 'block') {
    nav.style.display = 'none';
  }
  else {
    nav.style.display = 'block';
  }
});

// Photo Upload
const photoUploadForm = document.getElementById("photoupload");

if (photoUploadForm) {
  photoUploadForm.addEventListener("change", asyncPhotoUpload);
}
<commit_msg>Say farewell to jQuery<commit_after>import figureExtension from "./figure"
import asyncPhotoUpload from "./photoAjax"

require('../css/hjlog.scss');
require('script!showdown');
require('script!./highlight');

// Markdown rendering
const postBody = document.getElementsByClassName("markdown")[0];
if (postBody) {
  figureExtension(showdown);
  const md = postBody.innerText;
  const converter = new showdown.Converter({
    'extensions': ['figure'],
    'strikethrough': true,
    'tables': true,
    'noHeaderId': true});
  const html = converter.makeHtml(md);

  postBody.innerHTML = converter.makeHtml(md);
  postBody.style.display = "block";

  const dimmer = document.getElementsByClassName("dimmer")[0];
  dimmer.style.display = "none";
}

// Syntax highlighting
hljs.initHighlightingOnLoad();

// Responsive navbar
const trigger = document.getElementsByClassName('trigger')[0];
trigger.addEventListener("click", () => {
  const nav = document.getElementsByTagName('nav')[0];

  if (nav.style.display === 'block') {
    nav.style.display = 'none';
  }
  else {
    nav.style.display = 'block';
  }
});

// Photo Upload
const photoUploadForm = document.getElementById("photoupload");

if (photoUploadForm) {
  photoUploadForm.addEventListener("change", asyncPhotoUpload);
}
<|endoftext|>