<commit_before>const html = require('yo-yo')
const throttle = require('lodash.throttle')

function progressDetails (props) {
  return html`<span>${props.totalProgress || 0}%・${props.complete} / ${props.inProgress}・${props.totalUploadedSize} / ${props.totalSize}・↑ ${props.totalSpeed}/s・${props.totalETA}</span>`
}

const throttledProgressDetails = throttle(progressDetails, 1000, {leading: true, trailing: true})

const STATE_ERROR = 'error'
const STATE_WAITING = 'waiting'
const STATE_PREPROCESSING = 'preprocessing'
const STATE_UPLOADING = 'uploading'
const STATE_POSTPROCESSING = 'postprocessing'
const STATE_COMPLETE = 'complete'

function getUploadingState (props, files) {
  // if (props.error) {
  //   return STATE_ERROR
  // }

  if (props.isAllErrored) {
    return STATE_ERROR
  }

  // If ALL files have been completed, show the completed state.
  if (props.isAllComplete) {
    return STATE_COMPLETE
  }

  let state = STATE_WAITING
  const fileIDs = Object.keys(files)
  for (let i = 0; i < fileIDs.length; i++) {
    const progress = files[fileIDs[i]].progress
    // If ANY files are being uploaded right now, show the uploading state.
    if (progress.uploadStarted && !progress.uploadComplete) {
      return STATE_UPLOADING
    }
    // If files are being preprocessed AND postprocessed at this time, we show the
    // preprocess state. If any files are being uploaded we show uploading.
    if (progress.preprocess && state !== STATE_UPLOADING) {
      state = STATE_PREPROCESSING
    }
    // If NO files are being preprocessed or uploaded right now, but some files are
    // being postprocessed, show the postprocess state.
    if (progress.postprocess && state !== STATE_UPLOADING && state !== STATE_PREPROCESSING) {
      state = STATE_POSTPROCESSING
    }
  }
  return state
}

function calculateProcessingProgress (files) {
  // Collect pre or postprocessing progress states.
  const progresses = []
  Object.keys(files).forEach((fileID) => {
    const { progress } = files[fileID]
    if (progress.preprocess) {
      progresses.push(progress.preprocess)
    }
    if (progress.postprocess) {
      progresses.push(progress.postprocess)
    }
  })

  // In the future we should probably do this differently. For now we'll take the
  // mode and message from the first file…
  const { mode, message } = progresses[0]
  const value = progresses.filter(isDeterminate).reduce((total, progress, index, all) => {
    return total + progress.value / all.length
  }, 0)
  function isDeterminate (progress) {
    return progress.mode === 'determinate'
  }

  return {
    mode,
    message,
    value
  }
}

module.exports = (props) => {
  props = props || {}

  const uploadState = getUploadingState(props, props.files || {})

  let progressValue = props.totalProgress
  let progressMode
  let progressBarContent
  if (uploadState === STATE_PREPROCESSING || uploadState === STATE_POSTPROCESSING) {
    const progress = calculateProcessingProgress(props.files)
    progressMode = progress.mode
    if (progressMode === 'determinate') {
      progressValue = progress.value * 100
    }

    progressBarContent = ProgressBarProcessing(progress)
  } else if (uploadState === STATE_COMPLETE) {
    progressBarContent = ProgressBarComplete(props)
  } else if (uploadState === STATE_UPLOADING) {
    progressBarContent = ProgressBarUploading(props)
  } else if (uploadState === STATE_ERROR) {
    progressValue = undefined
    progressBarContent = ProgressBarError(props)
  }

  const width = typeof progressValue === 'number' ? progressValue : 100
  const isHidden = (uploadState === STATE_WAITING && props.hideUploadButton) ||
    (uploadState === STATE_WAITING && !props.newFiles > 0)

  return html`

      <div class="UppyStatusBar-progress ${progressMode ? `is-${progressMode}` : ''}"
           style="width: ${width}%"
           role="progressbar"
           aria-valuemin="0"
           aria-valuemax="100"
           aria-valuenow="${progressValue}">

      ${progressBarContent}

        ${props.newFiles && !props.hideUploadButton ? UploadBtn(props) : ''}
        ${props.error ? RetryBtn(props) : ''}

  `
}

const UploadBtn = (props) => {
  return html`<button type="button"
                      class="UppyStatusBar-actionBtn UppyStatusBar-actionBtn--upload"
                      aria-label="${props.i18n('uploadXFiles', { smart_count: props.newFiles })}"
                      onclick=${props.startUpload}>
                ${props.inProgress
                  ? props.i18n('uploadXNewFiles', { smart_count: props.newFiles })
                  : props.i18n('uploadXFiles', { smart_count: props.newFiles })
                }
              </button>`
}

const RetryBtn = (props) => {
  return html`<button type="button"
                      class="UppyStatusBar-actionBtn UppyStatusBar-actionBtn--retry"
                      aria-label="${props.i18n('retryUpload')}"
                      onclick=${props.retryAll}>
                ${props.i18n('retry')}
              </button>`
}

const ProgressBarProcessing = (props) => {
  const value = Math.round(props.value * 100)
  return html`

        ${props.mode === 'determinate' ? `${value}%・` : ''}
        ${props.message}

  `
}

const ProgressBarUploading = (props) => {
  return html`

      ${props.isUploadStarted && !props.isAllComplete
        ? !props.isAllPaused
          ? html`<div title="Uploading">${pauseResumeButtons(props)} Uploading... ${throttledProgressDetails(props)}</div>`
          : html`<div title="Paused">${pauseResumeButtons(props)} Paused・${props.totalProgress}%</div>`
        : null
      }

  `
}

const ProgressBarComplete = ({ totalProgress, i18n }) => {
  return html`

        <svg aria-hidden="true" class="UppyStatusBar-statusIndicator UppyIcon" width="18" height="17" viewBox="0 0 23 17">
          <path d="M8.944 17L0 7.865l2.555-2.61 6.39 6.525L20.41 0 23 2.645z" />
        </svg>
        ${i18n('uploadComplete')}・${totalProgress}%

  `
}

const ProgressBarError = ({ error, retryAll, i18n }) => {
  return html`

        ${i18n('uploadFailed')}.
        ${i18n('pleasePressRetry')}
        ?

  `
}

const pauseResumeButtons = (props) => {
  const { resumableUploads, isAllPaused, i18n } = props
  const title = resumableUploads
                ? isAllPaused
                  ? i18n('resumeUpload')
                  : i18n('pauseUpload')
                : i18n('cancelUpload')

  return html`<button title="${title}" class="UppyStatusBar-statusIndicator" type="button" onclick=${() => togglePauseResume(props)}>
    ${resumableUploads
      ? isAllPaused
        ? html`<svg aria-hidden="true" class="UppyIcon" width="15" height="17" viewBox="0 0 11 13">
          <path d="M1.26 12.534a.67.67 0 0 1-.674.012.67.67 0 0 1-.336-.583v-11C.25.724.38.5.586.382a.658.658 0 0 1 .673.012l9.165 5.5a.66.66 0 0 1 .325.57.66.66 0 0 1-.325.573l-9.166 5.5z" />
        </svg>`
        : html`<svg aria-hidden="true" class="UppyIcon" width="16" height="17" viewBox="0 0 12 13">
          <path d="M4.888.81v11.38c0 .446-.324.81-.722.81H2.722C2.324 13 2 12.636 2 12.19V.81c0-.446.324-.81.722-.81h1.444c.398 0 .722.364.722.81zM9.888.81v11.38c0 .446-.324.81-.722.81H7.722C7.324 13 7 12.636 7 12.19V.81c0-.446.324-.81.722-.81h1.444c.398 0 .722.364.722.81z"/>
        </svg>`
      : html`<svg aria-hidden="true" class="UppyIcon" width="16px" height="16px" viewBox="0 0 19 19">
        <path d="M17.318 17.232L9.94 9.854 9.586 9.5l-.354.354-7.378 7.378h.707l-.62-.62v.706L9.318 9.94l.354-.354-.354-.354L1.94 1.854v.707l.62-.62h-.706l7.378 7.378.354.354.354-.354 7.378-7.378h-.707l.622.62v-.706L9.854 9.232l-.354.354.354.354 7.378 7.378.708-.707-7.38-7.378v.708l7.38-7.38.353-.353-.353-.353-.622-.622-.353-.353-.354.352-7.378 7.38h.708L2.56 1.23 2.208.88l-.353.353-.622.62-.353.355.352.353 7.38 7.38v-.708l-7.38 7.38-.353.353.352.353.622.622.353.353.354-.353 7.38-7.38h-.708l7.38 7.38z"/>
      </svg>`
    }
  </button>`
}

const togglePauseResume = (props) => {
  if (props.isAllComplete) return

  if (!props.resumableUploads) {
    return props.cancelAll()
  }

  if (props.isAllPaused) {
    return props.resumeAll()
  }

  return props.pauseAll()
}
<commit_msg>only add aria-valuenow if progressMode === 'determinate'<commit_after>const html = require('yo-yo')
const throttle = require('lodash.throttle')

function progressDetails (props) {
  return html`<span>${props.totalProgress || 0}%・${props.complete} / ${props.inProgress}・${props.totalUploadedSize} / ${props.totalSize}・↑ ${props.totalSpeed}/s・${props.totalETA}</span>`
}

const throttledProgressDetails = throttle(progressDetails, 1000, {leading: true, trailing: true})

const STATE_ERROR = 'error'
const STATE_WAITING = 'waiting'
const STATE_PREPROCESSING = 'preprocessing'
const STATE_UPLOADING = 'uploading'
const STATE_POSTPROCESSING = 'postprocessing'
const STATE_COMPLETE = 'complete'

function getUploadingState (props, files) {
  // if (props.error) {
  //   return STATE_ERROR
  // }

  if (props.isAllErrored) {
    return STATE_ERROR
  }

  // If ALL files have been completed, show the completed state.
  if (props.isAllComplete) {
    return STATE_COMPLETE
  }

  let state = STATE_WAITING
  const fileIDs = Object.keys(files)
  for (let i = 0; i < fileIDs.length; i++) {
    const progress = files[fileIDs[i]].progress
    // If ANY files are being uploaded right now, show the uploading state.
    if (progress.uploadStarted && !progress.uploadComplete) {
      return STATE_UPLOADING
    }
    // If files are being preprocessed AND postprocessed at this time, we show the
    // preprocess state. If any files are being uploaded we show uploading.
    if (progress.preprocess && state !== STATE_UPLOADING) {
      state = STATE_PREPROCESSING
    }
    // If NO files are being preprocessed or uploaded right now, but some files are
    // being postprocessed, show the postprocess state.
    if (progress.postprocess && state !== STATE_UPLOADING && state !== STATE_PREPROCESSING) {
      state = STATE_POSTPROCESSING
    }
  }
  return state
}

function calculateProcessingProgress (files) {
  // Collect pre or postprocessing progress states.
  const progresses = []
  Object.keys(files).forEach((fileID) => {
    const { progress } = files[fileID]
    if (progress.preprocess) {
      progresses.push(progress.preprocess)
    }
    if (progress.postprocess) {
      progresses.push(progress.postprocess)
    }
  })

  // In the future we should probably do this differently. For now we'll take the
  // mode and message from the first file…
  const { mode, message } = progresses[0]
  const value = progresses.filter(isDeterminate).reduce((total, progress, index, all) => {
    return total + progress.value / all.length
  }, 0)
  function isDeterminate (progress) {
    return progress.mode === 'determinate'
  }

  return {
    mode,
    message,
    value
  }
}

module.exports = (props) => {
  props = props || {}

  const uploadState = getUploadingState(props, props.files || {})

  let progressValue = props.totalProgress
  let progressMode
  let progressBarContent
  if (uploadState === STATE_PREPROCESSING || uploadState === STATE_POSTPROCESSING) {
    const progress = calculateProcessingProgress(props.files)
    progressMode = progress.mode
    if (progressMode === 'determinate') {
      progressValue = progress.value * 100
    }

    progressBarContent = ProgressBarProcessing(progress)
  } else if (uploadState === STATE_COMPLETE) {
    progressBarContent = ProgressBarComplete(props)
  } else if (uploadState === STATE_UPLOADING) {
    progressBarContent = ProgressBarUploading(props)
  } else if (uploadState === STATE_ERROR) {
    progressValue = undefined
    progressBarContent = ProgressBarError(props)
  }

  const width = typeof progressValue === 'number' ? progressValue : 100
  const isHidden = (uploadState === STATE_WAITING && props.hideUploadButton) ||
    (uploadState === STATE_WAITING && !props.newFiles > 0)

  const statusBarEl = html`

      <div class="UppyStatusBar-progress ${progressMode ? `is-${progressMode}` : ''}"
           style="width: ${width}%"
           role="progressbar"
           aria-valuemin="0"
           aria-valuemax="100"
           aria-valuenow="${progressValue}">

      ${progressBarContent}

        ${props.newFiles && !props.hideUploadButton ? UploadBtn(props) : ''}
        ${props.error ? RetryBtn(props) : ''}

  `

  if (progressMode === 'determinate') {
    statusBarEl.setAttribute('aria-valuenow', progressValue)
  }

  return statusBarEl
}

const UploadBtn = (props) => {
  return html`<button type="button"
                      class="UppyStatusBar-actionBtn UppyStatusBar-actionBtn--upload"
                      aria-label="${props.i18n('uploadXFiles', { smart_count: props.newFiles })}"
                      onclick=${props.startUpload}>
                ${props.inProgress
                  ? props.i18n('uploadXNewFiles', { smart_count: props.newFiles })
                  : props.i18n('uploadXFiles', { smart_count: props.newFiles })
                }
              </button>`
}

const RetryBtn = (props) => {
  return html`<button type="button"
                      class="UppyStatusBar-actionBtn UppyStatusBar-actionBtn--retry"
                      aria-label="${props.i18n('retryUpload')}"
                      onclick=${props.retryAll}>
                ${props.i18n('retry')}
              </button>`
}

const ProgressBarProcessing = (props) => {
  const value = Math.round(props.value * 100)
  return html`

        ${props.mode === 'determinate' ? `${value}%・` : ''}
        ${props.message}

  `
}

const ProgressBarUploading = (props) => {
  return html`

      ${props.isUploadStarted && !props.isAllComplete
        ? !props.isAllPaused
          ? html`<div title="Uploading">${pauseResumeButtons(props)} Uploading... ${throttledProgressDetails(props)}</div>`
          : html`<div title="Paused">${pauseResumeButtons(props)} Paused・${props.totalProgress}%</div>`
        : null
      }

  `
}

const ProgressBarComplete = ({ totalProgress, i18n }) => {
  return html`

        <svg aria-hidden="true" class="UppyStatusBar-statusIndicator UppyIcon" width="18" height="17" viewBox="0 0 23 17">
          <path d="M8.944 17L0 7.865l2.555-2.61 6.39 6.525L20.41 0 23 2.645z" />
        </svg>
        ${i18n('uploadComplete')}・${totalProgress}%

  `
}

const ProgressBarError = ({ error, retryAll, i18n }) => {
  return html`

        ${i18n('uploadFailed')}.
        ${i18n('pleasePressRetry')}
        ?

  `
}

const pauseResumeButtons = (props) => {
  const { resumableUploads, isAllPaused, i18n } = props
  const title = resumableUploads
                ? isAllPaused
                  ? i18n('resumeUpload')
                  : i18n('pauseUpload')
                : i18n('cancelUpload')

  return html`<button title="${title}" class="UppyStatusBar-statusIndicator" type="button" onclick=${() => togglePauseResume(props)}>
    ${resumableUploads
      ? isAllPaused
        ? html`<svg aria-hidden="true" class="UppyIcon" width="15" height="17" viewBox="0 0 11 13">
          <path d="M1.26 12.534a.67.67 0 0 1-.674.012.67.67 0 0 1-.336-.583v-11C.25.724.38.5.586.382a.658.658 0 0 1 .673.012l9.165 5.5a.66.66 0 0 1 .325.57.66.66 0 0 1-.325.573l-9.166 5.5z" />
        </svg>`
        : html`<svg aria-hidden="true" class="UppyIcon" width="16" height="17" viewBox="0 0 12 13">
          <path d="M4.888.81v11.38c0 .446-.324.81-.722.81H2.722C2.324 13 2 12.636 2 12.19V.81c0-.446.324-.81.722-.81h1.444c.398 0 .722.364.722.81zM9.888.81v11.38c0 .446-.324.81-.722.81H7.722C7.324 13 7 12.636 7 12.19V.81c0-.446.324-.81.722-.81h1.444c.398 0 .722.364.722.81z"/>
        </svg>`
      : html`<svg aria-hidden="true" class="UppyIcon" width="16px" height="16px" viewBox="0 0 19 19">
        <path d="M17.318 17.232L9.94 9.854 9.586 9.5l-.354.354-7.378 7.378h.707l-.62-.62v.706L9.318 9.94l.354-.354-.354-.354L1.94 1.854v.707l.62-.62h-.706l7.378 7.378.354.354.354-.354 7.378-7.378h-.707l.622.62v-.706L9.854 9.232l-.354.354.354.354 7.378 7.378.708-.707-7.38-7.378v.708l7.38-7.38.353-.353-.353-.353-.622-.622-.353-.353-.354.352-7.378 7.38h.708L2.56 1.23 2.208.88l-.353.353-.622.62-.353.355.352.353 7.38 7.38v-.708l-7.38 7.38-.353.353.352.353.622.622.353.353.354-.353 7.38-7.38h-.708l7.38 7.38z"/>
      </svg>`
    }
  </button>`
}

const togglePauseResume = (props) => {
  if (props.isAllComplete) return

  if (!props.resumableUploads) {
    return props.cancelAll()
  }

  if (props.isAllPaused) {
    return props.resumeAll()
  }

  return props.pauseAll()
}
<|endoftext|>


<commit_before>/*global WebWorker:false */
(function () {
    'use strict';

    var worker = null,
        $output = null;

    $output = $('#worker-output');

    /**
    worker = new Worker('/js/example-worker.js');

    worker.addEventListener('message', function (event) {
        $output.text(event.data);
        return;
    })

    //worker.postMessage();
    /**/

    worker = new WebWorker('/js/example-worker.js');
    window.worker = worker;

    worker.on('message', function (event) {
        $output.text(event.data);
        return;
    });

    worker.on(WebWorker.Event.WORKER_LOADING, function () {
        console.log('worker loading');
        return;
    });

    worker.on(WebWorker.Event.WORKER_LOADED, function () {
        console.log('has loaded');
        worker.start();
        return;
    });

    worker.on(WebWorker.Event.WORKER_STARTING, function () {
        console.log('worker starting');
        return;
    });

    worker.on(WebWorker.Event.WORKER_STARTED, function () {
        console.log('worker started');
        return;
    });

    worker.load();

    return;
})();
<commit_msg>Add some event listeners on example page to track progress of worker.<commit_after>/*global WebWorker:false */
(function () {
    'use strict';

    var worker = null,
        $output = null;

    $output = $('#worker-output');

    /**
    worker = new Worker('/js/example-worker.js');

    worker.addEventListener('message', function (event) {
        $output.text(event.data);
        return;
    })

    //worker.postMessage();
    /**/

    worker = new WebWorker('/js/example-worker.js');
    window.worker = worker;

    worker.on('message', function (event) {
        $output.text(event.data);
        return;
    });

    worker.on(WebWorker.Event.WORKER_LOADING, function () {
        console.log('worker loading');
        return;
    });

    worker.on(WebWorker.Event.WORKER_LOADED, function () {
        console.log('worker loaded');
        worker.start();
        return;
    });

    worker.on(WebWorker.Event.WORKER_STARTING, function () {
        console.log('worker starting');
        return;
    });

    worker.on(WebWorker.Event.WORKER_STARTED, function () {
        console.log('worker started');
        worker.terminate();
        return;
    });

    worker.on(WebWorker.Event.WORKER_TERMINATING, function () {
        console.log('worker terminating');
        return;
    });

    worker.on(WebWorker.Event.WORKER_TERMINATED, function () {
        console.log('worker terminated');
        return;
    });

    worker.load();

    return;
})();
<|endoftext|>


<commit_before>/**
 * Copyright JS Foundation and other contributors, http://js.foundation
 *
 * 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.
 **/

var should = require("should");
var when = require("when");
var sinon = require("sinon");
var path = require("path");

var NR_TEST_UTILS = require("nr-test-utils");

var localfilesystem = NR_TEST_UTILS.require("@node-red/registry/lib/localfilesystem");

var resourcesDir = path.resolve(path.join(__dirname,"resources","local"));
var userDir = path.resolve(path.join(__dirname,"resources","userDir"));
var moduleDir = path.resolve(path.join(__dirname,"resources","local","TestNodeModule"));

var i18n = NR_TEST_UTILS.require("@node-red/util").i18n;

describe("red/nodes/registry/localfilesystem",function() {
    beforeEach(function() {
        stubs.push(sinon.stub(i18n,"registerMessageCatalog", function() { return Promise.resolve(); }));
    })

    var stubs = [];
    afterEach(function() {
        while(stubs.length) {
            stubs.pop().restore();
        }
    })
    function checkNodes(nodes,shouldHaveNodes,shouldNotHaveNodes,module) {
        for (var i=0;i<shouldHaveNodes.length;i++) {
            nodes.should.have.a.property(shouldHaveNodes[i]);
            nodes[shouldHaveNodes[i]].should.have.a.property('file');
	        nodes[shouldHaveNodes[i]].file.should.equal(path.resolve(nodes[shouldHaveNodes[i]].file));
            nodes[shouldHaveNodes[i]].should.have.a.property('module',module||'node-red');
            nodes[shouldHaveNodes[i]].should.have.a.property('name',shouldHaveNodes[i]);
        }
        for (i=0;i<shouldNotHaveNodes.length;i++) {
            nodes.should.not.have.a.property(shouldNotHaveNodes[i]);
        }
    }
    describe("#getNodeFiles",function() {
        it("Finds all the node files in the resources tree",function(done) {
            localfilesystem.init({settings:{coreNodesDir:resourcesDir}});
            var nodeList = localfilesystem.getNodeFiles(true);
            nodeList.should.have.a.property("node-red");
            var nm = nodeList['node-red'];
            nm.should.have.a.property('name','node-red');
            nm.should.have.a.property("nodes");
            var nodes = nm.nodes;
            checkNodes(nm.nodes,['TestNode1','MultipleNodes1','NestedNode','TestNode2','TestNode3','TestNode4'],['TestNodeModule']);
            i18n.registerMessageCatalog.called.should.be.true();
            i18n.registerMessageCatalog.lastCall.args[0].should.eql('node-red');
            i18n.registerMessageCatalog.lastCall.args[1].should.eql(path.resolve(path.join(resourcesDir,"locales")));
            i18n.registerMessageCatalog.lastCall.args[2].should.eql('messages.json');
            done();
        });
        it("Includes node files from settings",function(done) {
            localfilesystem.init({settings:{nodesIncludes:['TestNode1.js'],coreNodesDir:resourcesDir}});
            var nodeList = localfilesystem.getNodeFiles(true);
            nodeList.should.have.a.property("node-red");
            var nm = nodeList['node-red'];
            nm.should.have.a.property('name','node-red');
            nm.should.have.a.property("nodes");
            checkNodes(nm.nodes,['TestNode1'],['MultipleNodes1','NestedNode','TestNode2','TestNode3','TestNode4','TestNodeModule']);
            done();
        });
        it("Excludes node files from settings",function(done) {
            localfilesystem.init({settings:{nodesExcludes:['TestNode1.js'],coreNodesDir:resourcesDir}});
            var nodeList = localfilesystem.getNodeFiles(true);
            nodeList.should.have.a.property("node-red");
            var nm = nodeList['node-red'];
            nm.should.have.a.property('name','node-red');
            nm.should.have.a.property("nodes");
            checkNodes(nm.nodes,['MultipleNodes1','NestedNode','TestNode2','TestNode3','TestNode4'],['TestNode1','TestNodeModule']);
            done();
        });
        it("Finds nodes in userDir/nodes",function(done) {
            localfilesystem.init({settings:{userDir:userDir}});
            var nodeList = localfilesystem.getNodeFiles(true);
            nodeList.should.have.a.property("node-red");
            var nm = nodeList['node-red'];
            nm.should.have.a.property('name','node-red');
            nm.should.have.a.property("nodes");
            checkNodes(nm.nodes,['TestNode5'],['TestNode1']);
            done();
        });

        it("Finds nodes in settings.nodesDir (string)",function(done) {
            localfilesystem.init({settings:{nodesDir:userDir}});
            var nodeList = localfilesystem.getNodeFiles(true);
            nodeList.should.have.a.property("node-red");
            var nm = nodeList['node-red'];
            nm.should.have.a.property('name','node-red');
            nm.should.have.a.property("nodes");
            checkNodes(nm.nodes,['TestNode5'],['TestNode1']);
            done();
        });
        it("Finds nodes in settings.nodesDir (string,relative path)",function(done) {
            var relativeUserDir = path.join("test","unit","@node-red","registry","lib","resources","userDir");
            localfilesystem.init({settings:{nodesDir:relativeUserDir}});
            var nodeList = localfilesystem.getNodeFiles(true);
            nodeList.should.have.a.property("node-red");
            var nm = nodeList['node-red'];
            nm.should.have.a.property('name','node-red');
            nm.should.have.a.property("nodes");
            checkNodes(nm.nodes,['TestNode5'],['TestNode1']);
            done();
        });
        it("Finds nodes in settings.nodesDir (array)",function(done) {
            localfilesystem.init({settings:{nodesDir:[userDir]}});
            var nodeList = localfilesystem.getNodeFiles(true);
            nodeList.should.have.a.property("node-red");
            var nm = nodeList['node-red'];
            nm.should.have.a.property('name','node-red');
            nm.should.have.a.property("nodes");
            checkNodes(nm.nodes,['TestNode5'],['TestNode1']);
            done();
        });
        it("Finds nodes module path",function(done) {
            var _join = path.join;
            stubs.push(sinon.stub(path,"join",function() {
                if (arguments[0] == resourcesDir) {
                    // This stops the module tree scan from going any higher
                    // up the tree than resourcesDir.
                    return arguments[0];
                }
                return _join.apply(null,arguments);
            }));
            localfilesystem.init({settings:{coreNodesDir:moduleDir}});
            var nodeList = localfilesystem.getNodeFiles();
            nodeList.should.have.a.property("node-red");
            var nm = nodeList['node-red'];
            nm.should.have.a.property('name','node-red');
            nm.should.have.a.property("nodes");
            checkNodes(nm.nodes,[],['TestNode1']);

            nm = nodeList['TestNodeModule'];
            nm.should.have.a.property('name','TestNodeModule');
            nm.should.have.a.property("nodes");
            checkNodes(nm.nodes,['TestNodeMod1','TestNodeMod2'],[],'TestNodeModule');

            nm = nodeList['VersionMismatchModule'];
            nm.should.have.a.property('name','VersionMismatchModule');
            nm.should.have.a.property("nodes");
            checkNodes(nm.nodes,['VersionMismatchMod1','VersionMismatchMod2'],[],'VersionMismatchModule');

            i18n.registerMessageCatalog.called.should.be.true();
            i18n.registerMessageCatalog.lastCall.args[0].should.eql('node-red');
            i18n.registerMessageCatalog.lastCall.args[1].should.eql(path.resolve(path.join(moduleDir,"locales")));
            i18n.registerMessageCatalog.lastCall.args[2].should.eql('messages.json');

            done();
        });
        it.skip("finds locales directory");
        it.skip("finds icon path directory");
        it("scans icon files in the resources tree",function(done) {
            var count = 0;
            localfilesystem.init({

                // events:{emit:function(eventName,dir){
                //     if (count === 0) {
                //         eventName.should.equal("node-icon-dir");
                //         dir.name.should.equal("node-red");
                //         dir.icons.should.be.an.Array();
                //         count = 1;
                //     } else if (count === 1) {
                //         done();
                //     }
                // }},
                settings:{coreNodesDir:resourcesDir}
            });
            var list = localfilesystem.getNodeFiles(true);
            list.should.have.property("node-red");
            list["node-red"].should.have.property("icons");
            list["node-red"].icons.should.have.length(1);
            list["node-red"].icons[0].should.have.property("path",path.join(__dirname,"resources/local/NestedDirectoryNode/NestedNode/icons"))
            list["node-red"].icons[0].should.have.property("icons");
            list["node-red"].icons[0].icons.should.have.length(1);
            list["node-red"].icons[0].icons[0].should.eql("arrow-in.png");
            done();
        });
        it("scans icons dir in library",function(done) {
            var count = 0;
            localfilesystem.init({
                //
                // events:{emit:function(eventName,dir){
                //     eventName.should.equal("node-icon-dir");
                //     if (count === 0) {
                //         dir.name.should.equal("node-red");
                //         dir.icons.should.be.an.Array();
                //         count = 1;
                //     } else if (count === 1) {
                //         dir.name.should.equal("Library");
                //         dir.icons.should.be.an.Array();
                //         dir.icons.length.should.equal(1);
                //         dir.icons[0].should.be.equal("test_icon.png");
                //         done();
                //     }
                // }},
                settings:{userDir:userDir}
            });
            var list = localfilesystem.getNodeFiles(true);
            list.should.have.property("node-red");
            list["node-red"].should.have.property("icons");
            list["node-red"].icons.should.have.length(1);
            list["node-red"].icons[0].should.have.property("path",path.join(__dirname,"resources/userDir/lib/icons"))
            list["node-red"].icons[0].should.have.property("icons");
            list["node-red"].icons[0].icons.should.have.length(1);
            list["node-red"].icons[0].icons[0].should.eql("test_icon.png");
            done();
        });
    });
    describe("#getModuleFiles",function() {
        it("gets a nodes module files",function(done) {
            var _join = path.join;
            stubs.push(sinon.stub(path,"join",function() {
                if (arguments[0] == resourcesDir) {
                    // This stops the module tree scan from going any higher
                    // up the tree than resourcesDir.
                    return arguments[0];
                }
                return _join.apply(null,arguments);
            }));
            localfilesystem.init({settings:{coreNodesDir:moduleDir}});
            var nodeModule = localfilesystem.getModuleFiles('TestNodeModule');
            nodeModule.should.have.a.property('TestNodeModule');
            nodeModule['TestNodeModule'].should.have.a.property('name','TestNodeModule');
            nodeModule['TestNodeModule'].should.have.a.property('version','0.0.1');
            nodeModule['TestNodeModule'].should.have.a.property('nodes');
            checkNodes(nodeModule['TestNodeModule'].nodes,['TestNodeMod1','TestNodeMod2'],[],'TestNodeModule');

            nodeModule = localfilesystem.getModuleFiles('VersionMismatchModule');
            nodeModule.should.have.a.property('VersionMismatchModule');
            nodeModule['VersionMismatchModule'].should.have.a.property('redVersion','100.0.0');

            done();
        });
        it("throws an error if a node isn't found",function(done) {
            var _join = path.join;
            stubs.push(sinon.stub(path,"join",function() {
                if (arguments[0] == resourcesDir) {
                    // This stops the module tree scan from going any higher
                    // up the tree than resourcesDir.
                    return arguments[0];
                }
                return _join.apply(null,arguments);
            }));
            localfilesystem.init({settings:{coreNodesDir:moduleDir}});
            /*jshint immed: false */
            (function(){
                localfilesystem.getModuleFiles('WontExistModule');
            }).should.throw();
            done();
        });
        it.skip("finds locales directory");
        it.skip("finds icon path directory");
        it("scans icon files with a module file",function(done) {
            var _join = path.join;
            stubs.push(sinon.stub(path,"join",function() {
                if (arguments[0] == resourcesDir) {
                    // This stops the module tree scan from going any higher
                    // up the tree than resourcesDir.
                    return arguments[0];
                }
                return _join.apply(null,arguments);
            }));
            localfilesystem.init({

                // events:{emit:function(eventName,dir){
                //     eventName.should.equal("node-icon-dir");
                //     dir.name.should.equal("TestNodeModule");
                //     dir.icons.should.be.an.Array();
                //     done();
                // }},
                settings:{coreNodesDir:moduleDir}
            });
            var nodeModule = localfilesystem.getModuleFiles('TestNodeModule');
            nodeModule.should.have.property("TestNodeModule");
            nodeModule.TestNodeModule.should.have.property('icons');

            nodeModule.TestNodeModule.icons.should.have.length(1);
            nodeModule.TestNodeModule.icons[0].should.have.property("path");
            nodeModule.TestNodeModule.icons[0].should.have.property("icons");
            nodeModule.TestNodeModule.icons[0].icons[0].should.eql("arrow-in.png");
            done();
        });
    });
});
<commit_msg>Add unit test for module path<commit_after>/**
 * Copyright JS Foundation and other contributors, http://js.foundation
 *
 * 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.
 **/

var should = require("should");
var when = require("when");
var sinon = require("sinon");
var path = require("path");

var NR_TEST_UTILS = require("nr-test-utils");

var localfilesystem = NR_TEST_UTILS.require("@node-red/registry/lib/localfilesystem");

var resourcesDir = path.resolve(path.join(__dirname,"resources","local"));
var userDir = path.resolve(path.join(__dirname,"resources","userDir"));
var moduleDir = path.resolve(path.join(__dirname,"resources","local","TestNodeModule"));

var i18n = NR_TEST_UTILS.require("@node-red/util").i18n;

describe("red/nodes/registry/localfilesystem",function() {
    beforeEach(function() {
        stubs.push(sinon.stub(i18n,"registerMessageCatalog", function() { return Promise.resolve(); }));
    })

    var stubs = [];
    afterEach(function() {
        while(stubs.length) {
            stubs.pop().restore();
        }
    })
    function checkNodes(nodes,shouldHaveNodes,shouldNotHaveNodes,module) {
        for (var i=0;i<shouldHaveNodes.length;i++) {
            nodes.should.have.a.property(shouldHaveNodes[i]);
            nodes[shouldHaveNodes[i]].should.have.a.property('file');
	        nodes[shouldHaveNodes[i]].file.should.equal(path.resolve(nodes[shouldHaveNodes[i]].file));
            nodes[shouldHaveNodes[i]].should.have.a.property('module',module||'node-red');
            nodes[shouldHaveNodes[i]].should.have.a.property('name',shouldHaveNodes[i]);
        }
        for (i=0;i<shouldNotHaveNodes.length;i++) {
            nodes.should.not.have.a.property(shouldNotHaveNodes[i]);
        }
    }
    describe("#getNodeFiles",function() {
        it("Finds all the node files in the resources tree",function(done) {
            localfilesystem.init({settings:{coreNodesDir:resourcesDir}});
            var nodeList = localfilesystem.getNodeFiles(true);
            nodeList.should.have.a.property("node-red");
            var nm = nodeList['node-red'];
            nm.should.have.a.property('name','node-red');
            nm.should.have.a.property("nodes");
            var nodes = nm.nodes;
            checkNodes(nm.nodes,['TestNode1','MultipleNodes1','NestedNode','TestNode2','TestNode3','TestNode4'],['TestNodeModule']);
            i18n.registerMessageCatalog.called.should.be.true();
            i18n.registerMessageCatalog.lastCall.args[0].should.eql('node-red');
            i18n.registerMessageCatalog.lastCall.args[1].should.eql(path.resolve(path.join(resourcesDir,"locales")));
            i18n.registerMessageCatalog.lastCall.args[2].should.eql('messages.json');
            done();
        });
        it("Includes node files from settings",function(done) {
            localfilesystem.init({settings:{nodesIncludes:['TestNode1.js'],coreNodesDir:resourcesDir}});
            var nodeList = localfilesystem.getNodeFiles(true);
            nodeList.should.have.a.property("node-red");
            var nm = nodeList['node-red'];
            nm.should.have.a.property('name','node-red');
            nm.should.have.a.property("nodes");
            checkNodes(nm.nodes,['TestNode1'],['MultipleNodes1','NestedNode','TestNode2','TestNode3','TestNode4','TestNodeModule']);
            done();
        });
        it("Excludes node files from settings",function(done) {
            localfilesystem.init({settings:{nodesExcludes:['TestNode1.js'],coreNodesDir:resourcesDir}});
            var nodeList = localfilesystem.getNodeFiles(true);
            nodeList.should.have.a.property("node-red");
            var nm = nodeList['node-red'];
            nm.should.have.a.property('name','node-red');
            nm.should.have.a.property("nodes");
            checkNodes(nm.nodes,['MultipleNodes1','NestedNode','TestNode2','TestNode3','TestNode4'],['TestNode1','TestNodeModule']);
            done();
        });
        it("Finds nodes in userDir/nodes",function(done) {
            localfilesystem.init({settings:{userDir:userDir}});
            var nodeList = localfilesystem.getNodeFiles(true);
            nodeList.should.have.a.property("node-red");
            var nm = nodeList['node-red'];
            nm.should.have.a.property('name','node-red');
            nm.should.have.a.property("nodes");
            checkNodes(nm.nodes,['TestNode5'],['TestNode1']);
            done();
        });

        it("Finds nodes in settings.nodesDir (string)",function(done) {
            localfilesystem.init({settings:{nodesDir:userDir}});
            var nodeList = localfilesystem.getNodeFiles(true);
            nodeList.should.have.a.property("node-red");
            var nm = nodeList['node-red'];
            nm.should.have.a.property('name','node-red');
            nm.should.have.a.property("nodes");
            checkNodes(nm.nodes,['TestNode5'],['TestNode1']);
            done();
        });
        it("Finds nodes in settings.nodesDir (string,relative path)",function(done) {
            var relativeUserDir = path.join("test","unit","@node-red","registry","lib","resources","userDir");
            localfilesystem.init({settings:{nodesDir:relativeUserDir}});
            var nodeList = localfilesystem.getNodeFiles(true);
            nodeList.should.have.a.property("node-red");
            var nm = nodeList['node-red'];
            nm.should.have.a.property('name','node-red');
            nm.should.have.a.property("nodes");
            checkNodes(nm.nodes,['TestNode5'],['TestNode1']);
            done();
        });
        it("Finds nodes in settings.nodesDir (array)",function(done) {
            localfilesystem.init({settings:{nodesDir:[userDir]}});
            var nodeList = localfilesystem.getNodeFiles(true);
            nodeList.should.have.a.property("node-red");
            var nm = nodeList['node-red'];
            nm.should.have.a.property('name','node-red');
            nm.should.have.a.property("nodes");
            checkNodes(nm.nodes,['TestNode5'],['TestNode1']);
            done();
        });
        it("Finds nodes module path",function(done) {
            var _join = path.join;
            stubs.push(sinon.stub(path,"join",function() {
                if (arguments[0] == resourcesDir) {
                    // This stops the module tree scan from going any higher
                    // up the tree than resourcesDir.
                    return arguments[0];
                }
                return _join.apply(null,arguments);
            }));
            localfilesystem.init({settings:{coreNodesDir:moduleDir}});
            var nodeList = localfilesystem.getNodeFiles();
            nodeList.should.have.a.property("node-red");
            var nm = nodeList['node-red'];
            // The `node-red` module is loaded differently to those scanned for
            // It doesn't get the `path` property set. Maybe it should.
            nm.should.have.a.property('name','node-red');
            nm.should.have.a.property("nodes");
            checkNodes(nm.nodes,[],['TestNode1']);

            nm = nodeList['TestNodeModule'];
            nm.should.have.a.property('path')
            nm.should.have.a.property('name','TestNodeModule');
            nm.should.have.a.property("nodes");
            checkNodes(nm.nodes,['TestNodeMod1','TestNodeMod2'],[],'TestNodeModule');

            nm = nodeList['VersionMismatchModule'];
            nm.should.have.a.property('path')
            nm.should.have.a.property('name','VersionMismatchModule');
            nm.should.have.a.property("nodes");
            checkNodes(nm.nodes,['VersionMismatchMod1','VersionMismatchMod2'],[],'VersionMismatchModule');

            i18n.registerMessageCatalog.called.should.be.true();
            i18n.registerMessageCatalog.lastCall.args[0].should.eql('node-red');
            i18n.registerMessageCatalog.lastCall.args[1].should.eql(path.resolve(path.join(moduleDir,"locales")));
            i18n.registerMessageCatalog.lastCall.args[2].should.eql('messages.json');

            done();
        });
        it.skip("finds locales directory");
        it.skip("finds icon path directory");
        it("scans icon files in the resources tree",function(done) {
            var count = 0;
            localfilesystem.init({

                // events:{emit:function(eventName,dir){
                //     if (count === 0) {
                //         eventName.should.equal("node-icon-dir");
                //         dir.name.should.equal("node-red");
                //         dir.icons.should.be.an.Array();
                //         count = 1;
                //     } else if (count === 1) {
                //         done();
                //     }
                // }},
                settings:{coreNodesDir:resourcesDir}
            });
            var list = localfilesystem.getNodeFiles(true);
            list.should.have.property("node-red");
            list["node-red"].should.have.property("icons");
            list["node-red"].icons.should.have.length(1);
            list["node-red"].icons[0].should.have.property("path",path.join(__dirname,"resources/local/NestedDirectoryNode/NestedNode/icons"))
            list["node-red"].icons[0].should.have.property("icons");
            list["node-red"].icons[0].icons.should.have.length(1);
            list["node-red"].icons[0].icons[0].should.eql("arrow-in.png");
            done();
        });
        it("scans icons dir in library",function(done) {
            var count = 0;
            localfilesystem.init({
                //
                // events:{emit:function(eventName,dir){
                //     eventName.should.equal("node-icon-dir");
                //     if (count === 0) {
                //         dir.name.should.equal("node-red");
                //         dir.icons.should.be.an.Array();
                //         count = 1;
                //     } else if (count === 1) {
                //         dir.name.should.equal("Library");
                //         dir.icons.should.be.an.Array();
                //         dir.icons.length.should.equal(1);
                //         dir.icons[0].should.be.equal("test_icon.png");
                //         done();
                //     }
                // }},
                settings:{userDir:userDir}
            });
            var list = localfilesystem.getNodeFiles(true);
            list.should.have.property("node-red");
            list["node-red"].should.have.property("icons");
            list["node-red"].icons.should.have.length(1);
            list["node-red"].icons[0].should.have.property("path",path.join(__dirname,"resources/userDir/lib/icons"))
            list["node-red"].icons[0].should.have.property("icons");
            list["node-red"].icons[0].icons.should.have.length(1);
            list["node-red"].icons[0].icons[0].should.eql("test_icon.png");
            done();
        });
    });
    describe("#getModuleFiles",function() {
        it("gets a nodes module files",function(done) {
            var _join = path.join;
            stubs.push(sinon.stub(path,"join",function() {
                if (arguments[0] == resourcesDir) {
                    // This stops the module tree scan from going any higher
                    // up the tree than resourcesDir.
                    return arguments[0];
                }
                return _join.apply(null,arguments);
            }));
            localfilesystem.init({settings:{coreNodesDir:moduleDir}});
            var nodeModule = localfilesystem.getModuleFiles('TestNodeModule');
            nodeModule.should.have.a.property('TestNodeModule');
            nodeModule['TestNodeModule'].should.have.a.property('name','TestNodeModule');
            nodeModule['TestNodeModule'].should.have.a.property('version','0.0.1');
            nodeModule['TestNodeModule'].should.have.a.property('nodes');
            nodeModule['TestNodeModule'].should.have.a.property('path');

            checkNodes(nodeModule['TestNodeModule'].nodes,['TestNodeMod1','TestNodeMod2'],[],'TestNodeModule');

            nodeModule = localfilesystem.getModuleFiles('VersionMismatchModule');
            nodeModule.should.have.a.property('VersionMismatchModule');
            nodeModule['VersionMismatchModule'].should.have.a.property('redVersion','100.0.0');

            done();
        });
        it("throws an error if a node isn't found",function(done) {
            var _join = path.join;
            stubs.push(sinon.stub(path,"join",function() {
                if (arguments[0] == resourcesDir) {
                    // This stops the module tree scan from going any higher
                    // up the tree than resourcesDir.
                    return arguments[0];
                }
                return _join.apply(null,arguments);
            }));
            localfilesystem.init({settings:{coreNodesDir:moduleDir}});
            /*jshint immed: false */
            (function(){
                localfilesystem.getModuleFiles('WontExistModule');
            }).should.throw();
            done();
        });
        it.skip("finds locales directory");
        it.skip("finds icon path directory");
        it("scans icon files with a module file",function(done) {
            var _join = path.join;
            stubs.push(sinon.stub(path,"join",function() {
                if (arguments[0] == resourcesDir) {
                    // This stops the module tree scan from going any higher
                    // up the tree than resourcesDir.
                    return arguments[0];
                }
                return _join.apply(null,arguments);
            }));
            localfilesystem.init({

                // events:{emit:function(eventName,dir){
                //     eventName.should.equal("node-icon-dir");
                //     dir.name.should.equal("TestNodeModule");
                //     dir.icons.should.be.an.Array();
                //     done();
                // }},
                settings:{coreNodesDir:moduleDir}
            });
            var nodeModule = localfilesystem.getModuleFiles('TestNodeModule');
            nodeModule.should.have.property("TestNodeModule");
            nodeModule.TestNodeModule.should.have.property('icons');

            nodeModule.TestNodeModule.icons.should.have.length(1);
            nodeModule.TestNodeModule.icons[0].should.have.property("path");
            nodeModule.TestNodeModule.icons[0].should.have.property("icons");
            nodeModule.TestNodeModule.icons[0].icons[0].should.eql("arrow-in.png");
            done();
        });
    });
});
<|endoftext|>


<commit_before>(function () {

var Camera = function(game) {
    this.game = game;

    this.x = 0;
    this.y = 0;
    this.static = false;

    return this;
}

Camera.prototype.Init = function(game) {
    this.x = 0;
    this.y = 0;
    this.offset = {
        x: 0,
        y: 0
    }

    return this;
}

Camera.prototype.Update = function(game) {
    if(!this.static) {
        var player = game.Categories.Player;
        this.x = player.x - ((game.width/2)  - (player.width/2))  + this.offset.x;
        this.y = player.y - ((game.height/2) - (player.height/2)) + this.offset.y;
    }

    return this;
}

Camera.prototype.translate = function(vector) {
    if(this.static) {
        this.x += vector.x;
        this.y += vector.y;
    }
    else {
        this.offset.x += vector.x;
        this.offset.y += vector.y;
        // (x,y) will be updated on next Update
    }

    return this;
}

Camera.prototype.moveTo = function(vector) {
    this.static = true;
    this.x = vector.x;
    this.y = vector.y;

    return this;
}

Camera.prototype.followPlayer = function() {
    var player = this.game.Categories.Player;

    this.static = false;
    this.offset.x = (player.x - this.x) - ((this.game.width/2)  - (player.width/2));
    this.offset.y = (player.y - this.y) - ((this.game.height/2) - (player.height/2));
    // (x,y) will be updated on next Update

    return this;
}

Camera.prototype.unFollowPlayer = function() {
    var player = this.game.Categories.Player;

    this.static = true;
    this.x += offset.x;
    this.y += offset.y;
    this.offset.x = 0;
    this.offset.y = 0;

    return this;
}

var Plugin = {
    name: "camera-sidescroller",
    id: "core.camera-sidescroller",
    path: "Camera",
    construct: function(game) {
        return new Camera(game);
    }
}
Game.plugins.push(Plugin);

})()<commit_msg>Tweaked camera-sidescroller<commit_after>(function () {

var Camera = function(game) {
    this.game = game;

    this.x = 0;
    this.y = 0;
    this.offset = {
        x:0, y:0
    }
    this.static = false;

    return this;
}

Camera.prototype.Update = function(game) {
    if(!this.static) {
        var player = game.Categories.Player;
        this.x = player.x - ((game.width/2)  - (player.width/2))  + this.offset.x;
        this.y = player.y - ((game.height/2) - (player.height/2)) + this.offset.y;
    }

    return this;
}

Camera.prototype.translate = function(vector) {
    if(this.static) {
        this.x += vector.x;
        this.y += vector.y;
    }
    else {
        this.offset.x += vector.x;
        this.offset.y += vector.y;
        this.Update(this.game);
    }

    return this;
}

Camera.prototype.moveTo = function(vector) {
    this.static = true;
    this.x = vector.x;
    this.y = vector.y;

    return this;
}

Camera.prototype.followPlayer = function() {
    var player = this.game.Categories.Player;

    this.static = false;
    this.offset.x = (player.x - this.x) - ((this.game.width/2)  - (player.width/2));
    this.offset.y = (player.y - this.y) - ((this.game.height/2) - (player.height/2));
    this.Update(this.game);

    return this;
}

Camera.prototype.unFollowPlayer = function() {
    var player = this.game.Categories.Player;

    this.static = true;
    this.x += offset.x;
    this.y += offset.y;
    this.offset.x = 0;
    this.offset.y = 0;

    return this;
}

var Plugin = {
    name: "camera-sidescroller",
    id: "core.camera-sidescroller",
    path: "Camera",
    construct: function(game) {
        return new Camera(game);
    }
}
Game.plugins.push(Plugin);

})()<|endoftext|>


<commit_before>'use strict';
// problem: adding subtitles for videos on the web means learning code and takes a lot of time
// solution: create a way to produce the code for somebody to add to there video

// add an input for users video
	// create a url input
	// create button to insert input into video element
	// think of a way to link youtube videos

	// output times to file

// create input for subtitle text
	// add input elements to time list items
	// add a button to comit comment
	// add a button to edit comment

console.log('  ____                             _         _   _ \r\n \/ ___|  __ _ _   _  __ ___      _| | __    \/ | \/ |\r\n \\___ \\ \/ _` | | | |\/ _` \\ \\ \/\\ \/ \/ |\/ \/    | | | |\r\n  ___) | (_| | |_| | (_| |\\ V  V \/|   <     | |_| |\r\n |____\/ \\__, |\\__,_|\\__,_| \\_\/\\_\/ |_|\\_\\    |_(_)_|\r\n           |_|                                     ');
console.log('A PROGRAM FOR CREATING SUBTITLE FILES IN .vtt FORMAT');

// ** VARIABLES **
var videoUrl;
var loadButton = document.getElementById('load');
var playButton = document.getElementById('playButton');
var recordButton = document.getElementById('record');
var video = document.getElementById('video');
var buttonDown;
var buttonUp;
var listId = 1;
var captionSection = document.getElementById('captionSection');
var resetCaptionsButton;
var orderedList = document.getElementById('timeList');

var generateButton = document.getElementById('generate');
var createFileButton = document.getElementById('create');
var codeOutput = document.getElementById('code');

// ** FUNCTIONS **
// Add video to page
function loadVideo () {
	videoUrl = document.getElementById('userUrl').value;
	var video = document.getElementById('video');
	video.setAttribute('src', videoUrl);
	console.log(videoUrl);
	// Call function to check file extension and apply attribute type
	checkVideoType();
}

// Add function to set the video file type depending on the extension of the url
function checkVideoType () {
	var videoExtension = videoUrl.substr(videoUrl.lastIndexOf('.')+1);
	var video = document.getElementById('video');
	video.setAttribute('type', videoExtension);
	if (videoExtension !== 'mp4' && videoExtension !== 'ogg') {
		alert('Squawk does not support this file type and it may not behave as expected. Squawk supports .mp4 and .ogg formats please check your url for typos or find a different format of the video');
	}
}

// Add function that enables play button if url exhists
function enablePlayButton () {
	videoUrl = document.getElementById('userUrl').value;
	if (videoUrl === '') {
		playButton.setAttribute('disabled', '');
		alert('A url must be entered');
	} else {
		playButton.removeAttribute('disabled', '');
		console.log('The video has been loaded');
	}
}

// create a function that logs the time on mouse events
var logTime = function () {
	var timeStamp = video.currentTime.toFixed(3);
	return timeStamp;
}

// create two functions that update down and up time using logtime function
var logDownTime = function () {
	var time = logTime();
	buttonDown = time;
	console.log('Recording Started at: ' + buttonDown);
}

var logUpTime = function () {
	var time = logTime();
	buttonUp = time;
	console.log('Recording stopped at: ' + buttonUp);
}

// Create function to take the time stamp in seconds and convert it to .webvtt format (hh:mm:ss.sss)
function convertToTimeFormat (time) {
	var tick = time
	var hrs = Math.floor(tick/3600);
	tick = tick - 3600 * hrs;
	var mins = Math.floor(tick/60);
	tick = tick - 60 * mins;
	// Get seconds to 3 decimal places
	var secs = tick.toFixed(3);
	var tock = (hrs < 10 ? "0" : "" ) + hrs + ":"
         + (mins < 10 ? "0" : "" ) + mins + ":"
         + (secs < 10 ? "0" : "" ) + secs;
    // Return the output
    return tock;
}

// Create a caption list item
var addCaptionHolder = function (down, up) {
	console.log('Time stamp added to caption number: ' +listId);
	var li = document.createElement('li');// Create li
	li.setAttribute('id','caption' + listId);// Set unique id
	var input = document.createElement('input');// Create caption input
	input.setAttribute('id','input' + listId);// Set unique id
	input.setAttribute('tabindex', listId);// Set tab index
	input.setAttribute('type', 'text');// Set input type
	var saveButton = document.createElement('button');// Create save button
	// Set save button attribute to call function
	saveButton.setAttribute('onclick', 'saveEditCaption("' + 'input' + listId + '", "save' + listId +'")');
	var playSnippetButton = document.createElement('button');// Create play snippet button
	// Set play snippet button attribute to call function and pass the start record time value
	playSnippetButton.setAttribute('onclick', 'playSnippet("' +  listId + '", "' + down +'")');
	var deleteButton = document.createElement('button');// Create delete button
	// Set delete button attribute to call function
	deleteButton.setAttribute('onclick','deleteCaptionHolder("' + 'caption' + listId + '")');
	var startSpan = document.createElement('span');// Create spans for time stamp
	var endSpan = document.createElement('span');// Create spans for time stamp
	// Add each aditional list item to the end
	orderedList.appendChild(li);
	// Add children element to list item
	orderedList.lastChild.appendChild(input);
	orderedList.lastChild.appendChild(saveButton).innerHTML = 'Save';
	orderedList.lastChild.appendChild(playSnippetButton).innerHTML = 'Play snippet';
	orderedList.lastChild.appendChild(deleteButton).innerHTML = 'Delete';
	orderedList.lastChild.appendChild(startSpan);
	orderedList.lastChild.appendChild(endSpan);
	// Add id to elements
	saveButton.setAttribute('id','save' + listId);
	startSpan.setAttribute('id', 'rec_down' + listId);
	startSpan.className = 'rec_down';
	endSpan.setAttribute('id', 'rec_up' + listId);
	endSpan.className = 'rec_up';
	playSnippetButton.className = 'play';
	deleteButton.className = 'delete';
	// Send the time stamp to the convertToTimeFormat function
	// Add start and end time to spans
	startSpan.innerHTML = convertToTimeFormat(down);
	endSpan.innerHTML = convertToTimeFormat(up);
	listId += 1;// Add 1 to list item for next id
	// Disable generate button untill its saved
	console.log('not all captions are saved');
	generateButton.setAttribute('disabled', '');
	createFileButton.setAttribute('disabled','');
	codeOutput.setAttribute('placeholder','All captions must be saved before you can generate your file.');
}

// Create function to delete caption list item, pass caption id to function
function deleteCaptionHolder (captionID) {
	console.log('Deleted: ' + captionID);
	// Create a variable from element with passed id
	var item = document.getElementById(captionID);
	// Remove list item with passed id name from the list
	orderedList.removeChild(item);
	// Cycle through captions and see if they are saved using checkIfAllCaptionsAreComplete function
	var countList = orderedList.childNodes.length;
	checkIfAllCaptionsAreComplete(countList);
	// Call function to see if it was the last li and remove reset button if
	removeResetButton();
}

// Create a function to disable/enable caption input
function saveEditCaption (inputID, buttonID) {
	// Get elements by id supplied through the function values
	var item = document.getElementById(inputID);
	var item2 = document.getElementById(buttonID);
	// When user clicks button check if the disabled attribute is set
	// If it is already set remove it and change the button to save
	if (item.hasAttribute('disabled')) {
		item.removeAttribute('disabled');
		item2.innerHTML = 'Save';
		console.log(inputID + ' can be edited');
		if (item.parentElement.querySelector('.saveTick')) {
			var getSaveTick = item.parentElement.getElementsByClassName('saveTick');
			item.parentElement.removeChild(getSaveTick[0]);
			console.log('not all captions are saved');
			generateButton.setAttribute('disabled', '');
			createFileButton.setAttribute('disabled','');
			codeOutput.setAttribute('placeholder','All captions must be saved before you can generate your file.');
		} else {

		}

	} else {
	// if it is not set set it to disabled and change the button to edit
		item.setAttribute('disabled','');
		item2.innerHTML = 'Edit';
		console.log(inputID + ' has been saved');
		if (item.parentElement.querySelector('.saveTick')) {

		} else {
			var saveCheck = document.createElement('div');
			saveCheck.className = 'saveTick';
			saveCheck.appendChild(document.createTextNode('\u2714'));
			item.parentElement.appendChild(saveCheck);
		}
		// Cycle through captions and see if they are saved using checkIfAllCaptionsAreComplete function
		var countList = orderedList.childNodes.length;
		checkIfAllCaptionsAreComplete(countList);
	}
}

// Function to run through list items and see if they are saved, if they are enable generate button!
function checkIfAllCaptionsAreComplete (numberOfCaptionsToCheck) {
	for (var i = 1; i <= numberOfCaptionsToCheck; i += 1 ) {
		var checkForCompleteCaption = document.getElementById('caption' + i);
		if (checkForCompleteCaption === null) {
			numberOfCaptionsToCheck += 1;
		} else if (checkForCompleteCaption.querySelector('.saveTick')) {
			console.log(i + ' is saved');
		} else {
			break;
		}
		if (i === numberOfCaptionsToCheck) {
			console.log('All captions are saved!');
			generateButton.removeAttribute('disabled');
			codeOutput.setAttribute('placeholder','Press generate to preview your code here.');
		} else {

		}
	}
}

function playSnippet (captionID, startTime) {
	console.log('Play snippet ' + captionID + ' from: ' + startTime);
	video.currentTime = startTime;
	console.log(video.currentTime);
	video.play();
}

// Add reset all captions button if needed
function addResetButton () {
	// Check to see if the reset button already exhists
	if (captionSection.querySelector('#resetButton')) {

	} else {
	// If it doesnt then add the reset button
		console.log('Reset button added');
		resetCaptionsButton = document.createElement('button');// Create reset button
		// Set click attribute to call removeAllCaptions function
		resetCaptionsButton.setAttribute('onclick','removeAllCaptions("")');
		// Set the id of the button to be called in other functions
		resetCaptionsButton.setAttribute('id','resetButton');
		resetCaptionsButton.appendChild(document.createTextNode('Reset all Captions'));// Set button text
		captionSection.appendChild(resetCaptionsButton);// Add button as a child to the and of parent element
	}
}

// Create a function to remove reset button if no list items exhist
function removeResetButton () {
	if (orderedList.childNodes.length === 0) {
		// Get the reset button by id and remove it from the dom
		var removeResetButton = document.getElementById('resetButton');
		captionSection.removeChild(removeResetButton);
	}
}

// Create a function to remove all exhisting captions to be called by the reset button
function removeAllCaptions () {
	// while the list has a first child remove it (removes all children)
	while (orderedList.firstChild) {
		orderedList.removeChild(orderedList.firstChild)
	}
	console.log('Removed all captions & reset button');
	removeResetButton();// Call function to remove the reset button
	generateButton.setAttribute('disabled', '');// Disable generate button
	createFileButton.setAttribute('disabled','');// Disable create file button
	listId = 1;// Reset the captions id counter
}

// Create a function to grab data from each element
var getDataFromCaptions = function () {
	console.log('generate called');
	// Create a way to put data to text area
	codeOutput.innerHTML = '';
	// Add header to webvtt
	codeOutput.appendChild(document.createTextNode('WEBVTT' + '\u000a'));
	// Create a loop to go through each caption
	var captionCount = orderedList.childNodes.length;
	for (var i = 1; i <= captionCount; i += 1) {
		console.log('getting data from caption ' + i);
		// Get input data
		var input = document.getElementById('input' + i);
		// If the input is missing (has been deleted) increase the captionCount to compensate
		if (input === null) {
			captionCount += 1;
		} else {
			input = '- ' + input.value;
			// log it
			console.log(input);
			// Get time stamp data
			var startTime = document.getElementById('rec_down' + i);
			startTime = startTime.textContent;
			var endTime = document.getElementById('rec_up' + i);
			endTime = endTime.textContent;
			// log it
			console.log(startTime + ' --> ' + endTime);
			// Unicode - u000a line feed, u000d carriage return
			codeOutput.appendChild(document.createTextNode('\u000d' + i + '\u000a' ));
			codeOutput.appendChild(document.createTextNode(startTime + ' --> ' + endTime + '\u000a' ));
			codeOutput.appendChild(document.createTextNode(input + '\u000d'));
		}
	}
}

// Enable the record button & set the play/pause button
var enableRecord = function () {
	recordButton.removeAttribute('disabled', '');
	if (playButton.innerHTML === 'Play') {
		playButton.innerHTML = 'Pause';
	}
}

// Disable the record button & set the play/pause button
var disableRecord = function () {
	recordButton.setAttribute('disabled', '');
	if (playButton.innerHTML === 'Pause') {
		playButton.innerHTML = 'Play';
	}
}

// Toggle play/pause
var playPause = function () {
	if (playButton.innerHTML === 'Play') {
		video.play();
		playButton.innerHTML = 'Pause';
	} else if (playButton.innerHTML === 'Pause') {
		video.pause();
		playButton.innerHTML = 'Play';
	}
}

// ** RUN PROGRAM **

// Load video button
loadButton.onclick = function () {
	loadVideo();
	enablePlayButton();
}
// Play button
playButton.onclick = playPause;
// Record button
recordButton.onmousedown = logDownTime;
recordButton.onmouseup = function () {
	logUpTime();
	// generate list item
	addCaptionHolder(buttonDown, buttonUp);
	// call addResetButton function
	addResetButton();
}
// Generate button
generateButton.onclick = function () {
	getDataFromCaptions();
	createFileButton.removeAttribute('disabled');
}

video.addEventListener('play', enableRecord);
video.addEventListener('pause', disableRecord);
video.addEventListener('ended', disableRecord);

<commit_msg>js tidy<commit_after>'use strict';
/*
  ____                             _         _   _
 / ___|  __ _ _   _  __ ___      _| | __    / | / |
 \___ \ / _` | | | |/ _` \ \ /\ / / |/ /    | | | |
  ___) | (_| | |_| | (_| |\ V  V /|   <     | |_| |
 |____/ \__, |\__,_|\__,_| \_/\_/ |_|\_\    |_(_)_|
           |_|
*/
// problem: adding subtitles for videos on the web means learning code and takes a lot of time
// solution: create a way to produce the code for somebody to add to there video

// TO DO LIST //
// [x] Think of a way to link youtube videos.
// [x] Mobile support for record button.
// [x] Think of a way to load the output back into the video (subtitle preview).
// [x] Check if caption input contains text.

console.log('  ____                             _         _   _ \r\n \/ ___|  __ _ _   _  __ ___      _| | __    \/ | \/ |\r\n \\___ \\ \/ _` | | | |\/ _` \\ \\ \/\\ \/ \/ |\/ \/    | | | |\r\n  ___) | (_| | |_| | (_| |\\ V  V \/|   <     | |_| |\r\n |____\/ \\__, |\\__,_|\\__,_| \\_\/\\_\/ |_|\\_\\    |_(_)_|\r\n           |_|                                     ');
console.log('A PROGRAM FOR CREATING SUBTITLE FILES IN .vtt FORMAT');

// ** VARIABLES **
var videoUrl;
var loadButton = document.getElementById('load');
var playButton = document.getElementById('playButton');
var recordButton = document.getElementById('record');
var video = document.getElementById('video');
var buttonDown;
var buttonUp;
var listId = 1;
var captionSection = document.getElementById('captionSection');
var resetCaptionsButton;
var orderedList = document.getElementById('timeList');

var generateButton = document.getElementById('generate');
var createFileButton = document.getElementById('create');
var codeOutput = document.getElementById('code');

// ** FUNCTIONS **
// Add video to page
function loadVideo () {
	videoUrl = document.getElementById('userUrl').value;
	var video = document.getElementById('video');
	video.setAttribute('src', videoUrl);
	console.log(videoUrl);
	// Call function to check file extension and apply attribute type
	checkVideoType();
}

// Function to set the video file type depending on the extension of the url
function checkVideoType () {
	var videoExtension = videoUrl.substr(videoUrl.lastIndexOf('.')+1);
	var video = document.getElementById('video');
	video.setAttribute('type', videoExtension);
	if (videoExtension !== 'mp4' && videoExtension !== 'ogg') {
		alert('Squawk does not support this file type and it may not behave as expected. Squawk supports .mp4 and .ogg formats please check your url for typos or find a different format of the video');
	}
}

// Function that enables play button if url exhists
function enablePlayButton () {
	videoUrl = document.getElementById('userUrl').value;
	if (videoUrl === '') {
		playButton.setAttribute('disabled', '');
		alert('A url must be entered');
	} else {
		playButton.removeAttribute('disabled', '');
		console.log('The video has been loaded');
	}
}

// Function that logs the time on mouse events
var logTime = function () {
	var timeStamp = video.currentTime.toFixed(3);
	return timeStamp;
}

// Two functions that update down and up time using logtime function
var logDownTime = function () {
	var time = logTime();
	buttonDown = time;
	console.log('Recording Started at: ' + buttonDown);
}

var logUpTime = function () {
	var time = logTime();
	buttonUp = time;
	console.log('Recording stopped at: ' + buttonUp);
}

// Function to take the time stamp in seconds and convert it to .webvtt format (hh:mm:ss.sss)
function convertToTimeFormat (time) {
	var tick = time
	var hrs = Math.floor(tick/3600);
	tick = tick - 3600 * hrs;
	var mins = Math.floor(tick/60);
	tick = tick - 60 * mins;
	// Get seconds to 3 decimal places
	var secs = tick.toFixed(3);
	var tock = (hrs < 10 ? "0" : "" ) + hrs + ":"
         + (mins < 10 ? "0" : "" ) + mins + ":"
         + (secs < 10 ? "0" : "" ) + secs;
    // Return the output
    return tock;
}

// Create a caption list item
var addCaptionHolder = function (down, up) {
	console.log('Time stamp added to caption number: ' +listId);
	var li = document.createElement('li');// Create li
	li.setAttribute('id','caption' + listId);// Set unique id
	var input = document.createElement('input');// Create caption input
	input.setAttribute('id','input' + listId);// Set unique id
	input.setAttribute('tabindex', listId);// Set tab index
	input.setAttribute('type', 'text');// Set input type
	var saveButton = document.createElement('button');// Create save button
	// Set save button attribute to call function
	saveButton.setAttribute('onclick', 'saveEditCaption("' + 'input' + listId + '", "save' + listId +'")');
	var playSnippetButton = document.createElement('button');// Create play snippet button
	// Set play snippet button attribute to call function and pass the start record time value
	playSnippetButton.setAttribute('onclick', 'playSnippet("' +  listId + '", "' + down +'")');
	var deleteButton = document.createElement('button');// Create delete button
	// Set delete button attribute to call function
	deleteButton.setAttribute('onclick','deleteCaptionHolder("' + 'caption' + listId + '")');
	var startSpan = document.createElement('span');// Create spans for time stamp
	var endSpan = document.createElement('span');// Create spans for time stamp
	// Add each aditional list item to the end
	orderedList.appendChild(li);
	// Add children element to list item
	orderedList.lastChild.appendChild(input);
	orderedList.lastChild.appendChild(saveButton).innerHTML = 'Save';
	orderedList.lastChild.appendChild(playSnippetButton).innerHTML = 'Play snippet';
	orderedList.lastChild.appendChild(deleteButton).innerHTML = 'Delete';
	orderedList.lastChild.appendChild(startSpan);
	orderedList.lastChild.appendChild(endSpan);
	// Add id to elements
	saveButton.setAttribute('id','save' + listId);
	startSpan.setAttribute('id', 'rec_down' + listId);
	startSpan.className = 'rec_down';
	endSpan.setAttribute('id', 'rec_up' + listId);
	endSpan.className = 'rec_up';
	playSnippetButton.className = 'play';
	deleteButton.className = 'delete';
	// Send the time stamp to the convertToTimeFormat function
	// Add start and end time to spans
	startSpan.innerHTML = convertToTimeFormat(down);
	endSpan.innerHTML = convertToTimeFormat(up);
	listId += 1;// Add 1 to list item for next id
	// Disable generate button untill its saved
	console.log('not all captions are saved');
	generateButton.setAttribute('disabled', '');
	createFileButton.setAttribute('disabled','');
	codeOutput.setAttribute('placeholder','All captions must be saved before you can generate your file.');
}

// Create function to delete caption list item, pass caption id to function
function deleteCaptionHolder (captionID) {
	console.log('Deleted: ' + captionID);
	// Create a variable from element with passed id
	var item = document.getElementById(captionID);
	// Remove list item with passed id name from the list
	orderedList.removeChild(item);
	// Cycle through captions and see if they are saved using checkIfAllCaptionsAreComplete function
	var countList = orderedList.childNodes.length;
	checkIfAllCaptionsAreComplete(countList);
	// Call function to see if it was the last li and remove reset button if
	removeResetButton();
}

// Create a function to disable/enable caption input
function saveEditCaption (inputID, buttonID) {
	// Get elements by id supplied through the function values
	var item = document.getElementById(inputID);
	var item2 = document.getElementById(buttonID);
	// When user clicks button check if the disabled attribute is set
	// If it is already set remove it and change the button to save
	if (item.hasAttribute('disabled')) {
		item.removeAttribute('disabled');
		item2.innerHTML = 'Save';
		console.log(inputID + ' can be edited');
		if (item.parentElement.querySelector('.saveTick')) {
			var getSaveTick = item.parentElement.getElementsByClassName('saveTick');
			item.parentElement.removeChild(getSaveTick[0]);
			console.log('not all captions are saved');
			generateButton.setAttribute('disabled', '');
			createFileButton.setAttribute('disabled','');
			codeOutput.setAttribute('placeholder','All captions must be saved before you can generate your file.');
		} else {

		}

	} else {
	// if it is not set set it to disabled and change the button to edit
		item.setAttribute('disabled','');
		item2.innerHTML = 'Edit';
		console.log(inputID + ' has been saved');
		if (item.parentElement.querySelector('.saveTick')) {

		} else {
			var saveCheck = document.createElement('div');
			saveCheck.className = 'saveTick';
			saveCheck.appendChild(document.createTextNode('\u2714'));
			item.parentElement.appendChild(saveCheck);
		}
		// Cycle through captions and see if they are saved using checkIfAllCaptionsAreComplete function
		var countList = orderedList.childNodes.length;
		checkIfAllCaptionsAreComplete(countList);
	}
}

// Function to run through list items and see if they are saved, if they are enable generate button!
function checkIfAllCaptionsAreComplete (numberOfCaptionsToCheck) {
	for (var i = 1; i <= numberOfCaptionsToCheck; i += 1 ) {
		var checkForCompleteCaption = document.getElementById('caption' + i);
		if (checkForCompleteCaption === null) {
			numberOfCaptionsToCheck += 1;
		} else if (checkForCompleteCaption.querySelector('.saveTick')) {
			console.log(i + ' is saved');
		} else {
			break;
		}
		if (i === numberOfCaptionsToCheck) {
			console.log('All captions are saved!');
			generateButton.removeAttribute('disabled');
			codeOutput.setAttribute('placeholder','Press generate to preview your code here.');
		} else {

		}
	}
}

function playSnippet (captionID, startTime) {
	console.log('Play snippet ' + captionID + ' from: ' + startTime);
	video.currentTime = startTime;
	console.log(video.currentTime);
	video.play();
}

// Add reset all captions button if needed
function addResetButton () {
	// Check to see if the reset button already exhists
	if (captionSection.querySelector('#resetButton')) {

	} else {
	// If it doesnt then add the reset button
		console.log('Reset button added');
		resetCaptionsButton = document.createElement('button');// Create reset button
		// Set click attribute to call removeAllCaptions function
		resetCaptionsButton.setAttribute('onclick','removeAllCaptions("")');
		// Set the id of the button to be called in other functions
		resetCaptionsButton.setAttribute('id','resetButton');
		resetCaptionsButton.appendChild(document.createTextNode('Reset all Captions'));// Set button text
		captionSection.appendChild(resetCaptionsButton);// Add button as a child to the and of parent element
	}
}

// Create a function to remove reset button if no list items exhist
function removeResetButton () {
	if (orderedList.childNodes.length === 0) {
		// Get the reset button by id and remove it from the dom
		var removeResetButton = document.getElementById('resetButton');
		captionSection.removeChild(removeResetButton);
	}
}

// Create a function to remove all exhisting captions to be called by the reset button
function removeAllCaptions () {
	// while the list has a first child remove it (removes all children)
	while (orderedList.firstChild) {
		orderedList.removeChild(orderedList.firstChild)
	}
	console.log('Removed all captions & reset button');
	removeResetButton();// Call function to remove the reset button
	generateButton.setAttribute('disabled', '');// Disable generate button
	createFileButton.setAttribute('disabled','');// Disable create file button
	listId = 1;// Reset the captions id counter
}

// Function to grab data from each element
var getDataFromCaptions = function () {
	console.log('generate called');
	// Create a way to put data to text area
	codeOutput.innerHTML = '';
	// Add header to webvtt
	codeOutput.appendChild(document.createTextNode('WEBVTT' + '\u000a'));
	// Create a loop to go through each caption
	var captionCount = orderedList.childNodes.length;
	for (var i = 1; i <= captionCount; i += 1) {
		console.log('getting data from caption ' + i);
		// Get input data
		var input = document.getElementById('input' + i);
		// If the input is missing (has been deleted) increase the captionCount to compensate
		if (input === null) {
			captionCount += 1;
		} else {
			input = '- ' + input.value;
			// log it
			console.log(input);
			// Get time stamp data
			var startTime = document.getElementById('rec_down' + i);
			startTime = startTime.textContent;
			var endTime = document.getElementById('rec_up' + i);
			endTime = endTime.textContent;
			// log it
			console.log(startTime + ' --> ' + endTime);
			// Unicode - u000a line feed, u000d carriage return
			codeOutput.appendChild(document.createTextNode('\u000d' + i + '\u000a' ));
			codeOutput.appendChild(document.createTextNode(startTime + ' --> ' + endTime + '\u000a' ));
			codeOutput.appendChild(document.createTextNode(input + '\u000d'));
		}
	}
}

// Enable the record button & set the play/pause button
var enableRecord = function () {
	recordButton.removeAttribute('disabled', '');
	if (playButton.innerHTML === 'Play') {
		playButton.innerHTML = 'Pause';
	}
}

// Disable the record button & set the play/pause button
var disableRecord = function () {
	recordButton.setAttribute('disabled', '');
	if (playButton.innerHTML === 'Pause') {
		playButton.innerHTML = 'Play';
	}
}

// Toggle play/pause
var playPause = function () {
	if (playButton.innerHTML === 'Play') {
		video.play();
		playButton.innerHTML = 'Pause';
	} else if (playButton.innerHTML === 'Pause') {
		video.pause();
		playButton.innerHTML = 'Play';
	}
}

// ** RUN PROGRAM **

// Load video button
loadButton.onclick = function () {
	loadVideo();
	enablePlayButton();
}
// Play button
playButton.onclick = playPause;
// Record button
recordButton.onmousedown = logDownTime;
recordButton.onmouseup = function () {
	logUpTime();
	// generate list item
	addCaptionHolder(buttonDown, buttonUp);
	// call addResetButton function
	addResetButton();
}
// Generate button
generateButton.onclick = function () {
	getDataFromCaptions();
	createFileButton.removeAttribute('disabled');
}

video.addEventListener('play', enableRecord);
video.addEventListener('pause', disableRecord);
video.addEventListener('ended', disableRecord);

<|endoftext|>


<commit_before>/**
 * ownCloud - ocsms
 *
 * This file is licensed under the Affero General Public License version 3 or
 * later. See the COPYING file.
 *
 * @author Loic Blot <loic.blot@unix-experience.fr>
 * @copyright Loic Blot 2014
 */

// Some global vars to improve performances
var selectedConversation = null;

// Source: http://www.sitepoint.com/url-parameters-jquery/
$.urlParam = function(name){
	var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href);
	if (results == null) {
		return null;
	}
	else {
		return results[1] || 0;
	}
}

function fetchConversation(phoneNumber) {
	$.getJSON(OC.generateUrl('/apps/ocsms/get/conversation'),
		{'phoneNumber': phoneNumber},
		function(jsondata, status) {
			// Improve jQuery performance
			var conversationBuf = "";
			// Improve JS performance
			var msgClass = '';
			var unixDate = '';
			var formatedDate = '';
			var months = ['Jan.', 'Feb.', 'Mar.', 'Apr.', 'May', 'Jun.', 'Jul.', 'Aug.', 'Sep.',
				'Oct.', 'Nov.', 'Dec.'];

			$.each(jsondata["conversation"], function(id, vals) {
				if (vals["type"] == 1) {
					msgClass = "msg-recv";
				}
				else if (vals["type"] == 2) {
					msgClass = "msg-sent";
				}
				else {
					msgClass = '';
				}

				// Multiplicate ID to permit date to use it properly
				msgDate = new Date(id*1);
				formatedDate = msgDate.getDate() + " " + months[msgDate.getMonth()-1] + " " +
					msgDate.getHours() + ":" + msgDate.getMinutes();

				conversationBuf += '

' +
					vals["msg"] + '

' +
					formatedDate + '

';
			});

			$('#app-content').html(conversationBuf);
			$('#app-content').scrollTop(1E10);
		}
	);
}

function changeSelectedConversation(item) {
	if (selectedConversation != null) {
		selectedConversation.removeClass('active');
	}
	selectedConversation = $(this);
	selectedConversation.addClass('active');
}

(function ($, OC) {
	$(document).ready(function () {
		// Now bind the events when we click on the phone number
		$('#app-navigation').find('a').on('click', function (event) {
			OC.Util.History.pushState('feed=' + $(this).attr('nav-feed'));
			event.preventDefault();
		});

		$.getJSON(OC.generateUrl('/apps/ocsms/get/peerlist'), function(jsondata, status) {
			// Use a buffer for better jQuery performance
			var peerListBuf = "";

			$.each(jsondata['phonelist'], function(id, val) {
				peerListBuf += '
' + val + '
';
			});

			$('#app-mailbox-peers ul').html(peerListBuf);

			// Now bind the events when we click on the phone number
			$('#app-mailbox-peers').find('a[mailbox-navigation]').on('click', function (event) {
				var phoneNumber = $(this).attr('mailbox-navigation');
				OC.Util.History.pushState('phonenumber=' + phoneNumber);
				fetchConversation(phoneNumber);
				changeSelectedConversation($(this));
				event.preventDefault();
			});

			var urlPhoneNumber = decodeURIComponent($.urlParam('phonenumber'));
			if (urlPhoneNumber != null) {
				fetchConversation(urlPhoneNumber);

				var pObject = $("a[mailbox-navigation='" + urlPhoneNumber + "']");
				if (pObject != null) {
					changeSelectedConversation(pObject);
				}
			}
	     });
	});

})(jQuery, OC);
<commit_msg>Format minutes & hour with prefixed zero<commit_after>/**
 * ownCloud - ocsms
 *
 * This file is licensed under the Affero General Public License version 3 or
 * later. See the COPYING file.
 *
 * @author Loic Blot <loic.blot@unix-experience.fr>
 * @copyright Loic Blot 2014
 */

// Some global vars to improve performances
var selectedConversation = null;

// Source: http://www.sitepoint.com/url-parameters-jquery/
$.urlParam = function(name){
	var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href);
	if (results == null) {
		return null;
	}
	else {
		return results[1] || 0;
	}
}

function fetchConversation(phoneNumber) {
	$.getJSON(OC.generateUrl('/apps/ocsms/get/conversation'),
		{'phoneNumber': phoneNumber},
		function(jsondata, status) {
			// Improve jQuery performance
			var conversationBuf = "";
			// Improve JS performance
			var msgClass = '';
			var unixDate = '';
			var formatedDate = '';
			var formatedHour = '00';
			var formatedMin = '00';
			var months = ['Jan.', 'Feb.', 'Mar.', 'Apr.', 'May', 'Jun.', 'Jul.', 'Aug.', 'Sep.',
				'Oct.', 'Nov.', 'Dec.'];

			$.each(jsondata["conversation"], function(id, vals) {
				if (vals["type"] == 1) {
					msgClass = "msg-recv";
				}
				else if (vals["type"] == 2) {
					msgClass = "msg-sent";
				}
				else {
					msgClass = '';
				}

				// Multiplicate ID to permit date to use it properly
				msgDate = new Date(id*1);

				formatedHour = msgDate.getHours();
				if (formatedHour < 10) {
					formatedHour = '0' + formatedHour;
				}

				formatedMin = msgDate.getMinutes();
				if (formatedMin < 10) {
					formatedMin = '0' + formatedMin;
				}
				formatedDate = msgDate.getDate() + " " + months[msgDate.getMonth()-1] + " " +
					formatedHour + ":" + formatedMin;

				conversationBuf += '

' +
					vals["msg"] + '

' +
					formatedDate + '

';
			});

			$('#app-content').html(conversationBuf);
			$('#app-content').scrollTop(1E10);
		}
	);
}

function changeSelectedConversation(item) {
	if (selectedConversation != null) {
		selectedConversation.removeClass('active');
	}
	selectedConversation = $(this);
	selectedConversation.addClass('active');
}

(function ($, OC) {
	$(document).ready(function () {
		// Now bind the events when we click on the phone number
		$('#app-navigation').find('a').on('click', function (event) {
			OC.Util.History.pushState('feed=' + $(this).attr('nav-feed'));
			event.preventDefault();
		});

		$.getJSON(OC.generateUrl('/apps/ocsms/get/peerlist'), function(jsondata, status) {
			// Use a buffer for better jQuery performance
			var peerListBuf = "";

			$.each(jsondata['phonelist'], function(id, val) {
				peerListBuf += '
' + val + '
';
			});

			$('#app-mailbox-peers ul').html(peerListBuf);

			// Now bind the events when we click on the phone number
			$('#app-mailbox-peers').find('a[mailbox-navigation]').on('click', function (event) {
				var phoneNumber = $(this).attr('mailbox-navigation');
				OC.Util.History.pushState('phonenumber=' + phoneNumber);
				fetchConversation(phoneNumber);
				changeSelectedConversation($(this));
				event.preventDefault();
			});

			var urlPhoneNumber = decodeURIComponent($.urlParam('phonenumber'));
			if (urlPhoneNumber != null) {
				fetchConversation(urlPhoneNumber);

				var pObject = $("a[mailbox-navigation='" + urlPhoneNumber + "']");
				if (pObject != null) {
					changeSelectedConversation(pObject);
				}
			}
	     });
	});

})(jQuery, OC);
<|endoftext|>