<commit_before>/** @format */
import statemachine from "./statemachine"
const korpApp = angular.module("korpApp")

korpApp.directive("textReaderCtrl", ($timeout) => ({
    controller($scope, backend) {
        const s = $scope

        s.loading = true
        s.newDynamicTab()

        s.closeTab = function (idx, e) {
            e.preventDefault()
            s.textTabs.splice(idx, 1)
            s.closeDynamicTab()
        }

        const corpus = s.inData.corpus
        s.corpusObj = settings.corpora[corpus]
        const sentenceId = s.inData.sentenceId
        backend.getDataForReadingMode(corpus, sentenceId).then(function (data) {
            new Promise((resolve, reject) => {
                resolve(prepareData(data.kwic[0], s.corpusObj))
            }).then((document) => {
                s.data = { corpus, sentenceId, document }
                $timeout(() => (s.loading = false), 0)
            })
        })

        s.onentry = function () {
            s.$broadcast("on-entry")
        }
        s.onexit = function () {
            s.$broadcast("on-exit")
        }
    },
}))

korpApp.directive("textReader", function ($compile) {
    return {
        scope: false,
        link: function (scope, element) {
            const componentName = scope.corpusObj["reading_mode"].component

            const kebabize = (str) => {
                return str
                    .split("")
                    .map((letter, idx) => {
                        return letter.toUpperCase() === letter
                            ? `${idx !== 0 ? "-" : ""}${letter.toLowerCase()}`
                            : letter
                    })
                    .join("")
            }

            const actualComponentName = kebabize(componentName)

            var generatedTemplate = `<${actualComponentName} data="data" word-click="wordClick"></${actualComponentName}>`
            element.append($compile(generatedTemplate)(scope))

            scope.selectedToken = {}

            scope.wordClick = (token) => {
                statemachine.send("select_word", {
                    sentenceData: scope.data.document.structs,
                    wordData: token.attrs,
                    corpus: scope.data.corpus,
                    tokens: token.currentSentence,
                    inReadingMode: true,
                })
                scope.selectedToken = token
            }

            scope.$on("on-entry", function () {
                if (scope.data) {
                    scope.wordClick(scope.selectedToken)
                }
            })

            scope.$on("on-exit", function () {})

            scope.wordClick({})
        },
    }
})

function prepareData(kwic, settings) {
    const newTokens = _prepareData(kwic.tokens, 0, settings["reading_mode"].groupElement, false)
    delete kwic.tokens
    kwic.tokens = newTokens
    return kwic
}

/**
if groupElement is set to anything, result will be a list of tokens for each
sentence or whatever groupElement is set to
*/
function _prepareData(tokens, start, groupElement, inGroup) {
    const open = {}
    const newTokens = []

    // TODO: sentence is hard-coded, not good?
    let currentSentence = []
    for (let i = start; i < tokens.length; i++) {
        let token = tokens[i]
        // first check if we should do recursive call
        let done = false
        if ("structs" in token) {
            if ("open" in token.structs) {
                token["open"] = []
                for (let fieldObj of token.structs.open) {
                    const keyName = _.keys(fieldObj)[0]

                    if (!inGroup && keyName === groupElement) {
                        done = true
                        const innerTokens = _prepareData(tokens, i, groupElement, true)
                        i = i + innerTokens.length - 1
                        token = {
                            tokens: innerTokens,
                            attrs: {},
                        }
                        for (let subField in fieldObj[keyName]) {
                            token.attrs[subField] = fieldObj[keyName][subField]
                        }
                    }
                }
            }
        }

        token.head = (token._head || "").replace(/\\s/g, " ").replace(/\\n/g, "\n").replace(/\\t/g, "\t")
        token.tail = (token._tail || "").replace(/\\s/g, " ").replace(/\\n/g, "\n").replace(/\\t/g, "\t")
        currentSentence.push(token)
        // if no call was made, do the other thing
        if (!done) {
            if ("structs" in token && "open" in token.structs) {
                for (let fieldObj of token.structs.open) {
                    const keyName = _.keys(fieldObj)[0]
                    open[keyName] = {}
                    for (let subField in fieldObj[keyName]) {
                        open[keyName][keyName + "_" + subField] = fieldObj[keyName][subField]
                    }
                }
            }

            for (let field in open) {
                for (let subField in open[field]) {
                    if (open[field][subField]) {
                        token[subField] = open[field][subField]
                    }
                }
            }

            const actualCurrentSentence = currentSentence

            if ("structs" in token && "close" in token.structs) {
                token["close"] = []
                for (let field of token.structs.close) {
                    if (field === groupElement) {
                        delete token.structs
                        newTokens.push({ attrs: token, currentSentence: actualCurrentSentence })
                        return newTokens
                    } else {
                        if (field === "sentence") {
                            currentSentence = []
                        }
                        token["close"].push(field)
                        delete open[field]
                    }
                }
            }

            delete token.structs
            token = { attrs: token, currentSentence: actualCurrentSentence }
        }
        newTokens.push(token)
    }

    return newTokens
}
<commit_msg>snake -> camel case<commit_after>/** @format */
import statemachine from "./statemachine"
const korpApp = angular.module("korpApp")

korpApp.directive("textReaderCtrl", ($timeout) => ({
    controller($scope, backend) {
        const s = $scope

        s.loading = true
        s.newDynamicTab()

        s.closeTab = function (idx, e) {
            e.preventDefault()
            s.textTabs.splice(idx, 1)
            s.closeDynamicTab()
        }

        const corpus = s.inData.corpus
        s.corpusObj = settings.corpora[corpus]
        const sentenceId = s.inData.sentenceId
        backend.getDataForReadingMode(corpus, sentenceId).then(function (data) {
            new Promise((resolve, reject) => {
                resolve(prepareData(data.kwic[0], s.corpusObj))
            }).then((document) => {
                s.data = { corpus, sentenceId, document }
                $timeout(() => (s.loading = false), 0)
            })
        })

        s.onentry = function () {
            s.$broadcast("on-entry")
        }
        s.onexit = function () {
            s.$broadcast("on-exit")
        }
    },
}))

korpApp.directive("textReader", function ($compile) {
    return {
        scope: false,
        link: function (scope, element) {
            const componentName = scope.corpusObj["reading_mode"].component

            const kebabize = (str) => {
                return str
                    .split("")
                    .map((letter, idx) => {
                        return letter.toUpperCase() === letter
                            ? `${idx !== 0 ? "-" : ""}${letter.toLowerCase()}`
                            : letter
                    })
                    .join("")
            }

            const actualComponentName = kebabize(componentName)

            var generatedTemplate = `<${actualComponentName} data="data" word-click="wordClick"></${actualComponentName}>`
            element.append($compile(generatedTemplate)(scope))

            scope.selectedToken = {}

            scope.wordClick = (token) => {
                statemachine.send("select_word", {
                    sentenceData: scope.data.document.structs,
                    wordData: token.attrs,
                    corpus: scope.data.corpus,
                    tokens: token.currentSentence,
                    inReadingMode: true,
                })
                scope.selectedToken = token
            }

            scope.$on("on-entry", function () {
                if (scope.data) {
                    scope.wordClick(scope.selectedToken)
                }
            })

            scope.$on("on-exit", function () {})

            scope.wordClick({})
        },
    }
})

function prepareData(kwic, settings) {
    const newTokens = _prepareData(kwic.tokens, 0, settings["reading_mode"]["group_element"], false)
    delete kwic.tokens
    kwic.tokens = newTokens
    return kwic
}

/**
if groupElement is set to anything, result will be a list of tokens for each
sentence or whatever groupElement is set to
*/
function _prepareData(tokens, start, groupElement, inGroup) {
    const open = {}
    const newTokens = []

    // TODO: sentence is hard-coded, not good?
    let currentSentence = []
    for (let i = start; i < tokens.length; i++) {
        let token = tokens[i]
        // first check if we should do recursive call
        let done = false
        if ("structs" in token) {
            if ("open" in token.structs) {
                token["open"] = []
                for (let fieldObj of token.structs.open) {
                    const keyName = _.keys(fieldObj)[0]

                    if (!inGroup && keyName === groupElement) {
                        done = true
                        const innerTokens = _prepareData(tokens, i, groupElement, true)
                        i = i + innerTokens.length - 1
                        token = {
                            tokens: innerTokens,
                            attrs: {},
                        }
                        for (let subField in fieldObj[keyName]) {
                            token.attrs[subField] = fieldObj[keyName][subField]
                        }
                    }
                }
            }
        }

        token.head = (token._head || "").replace(/\\s/g, " ").replace(/\\n/g, "\n").replace(/\\t/g, "\t")
        token.tail = (token._tail || "").replace(/\\s/g, " ").replace(/\\n/g, "\n").replace(/\\t/g, "\t")
        currentSentence.push(token)
        // if no call was made, do the other thing
        if (!done) {
            if ("structs" in token && "open" in token.structs) {
                for (let fieldObj of token.structs.open) {
                    const keyName = _.keys(fieldObj)[0]
                    open[keyName] = {}
                    for (let subField in fieldObj[keyName]) {
                        open[keyName][keyName + "_" + subField] = fieldObj[keyName][subField]
                    }
                }
            }

            for (let field in open) {
                for (let subField in open[field]) {
                    if (open[field][subField]) {
                        token[subField] = open[field][subField]
                    }
                }
            }

            const actualCurrentSentence = currentSentence

            if ("structs" in token && "close" in token.structs) {
                token["close"] = []
                for (let field of token.structs.close) {
                    if (field === groupElement) {
                        delete token.structs
                        newTokens.push({ attrs: token, currentSentence: actualCurrentSentence })
                        return newTokens
                    } else {
                        if (field === "sentence") {
                            currentSentence = []
                        }
                        token["close"].push(field)
                        delete open[field]
                    }
                }
            }

            delete token.structs
            token = { attrs: token, currentSentence: actualCurrentSentence }
        }
        newTokens.push(token)
    }

    return newTokens
}
<|endoftext|>


<commit_before>angular.module('media_manager')
.directive('dropletThumb', [function(){
  return {
    scope: {
      image: '=ngModel'
    },
    restrict: 'EA',
    replace: true,
    template: '',

  };
}]);
<commit_msg>Fixed dropletThumb directive using ngSrc.<commit_after>angular.module('media_manager')
.directive('dropletThumb', [function(){
  return {
    scope: {
      image: '=ngModel'
    },
    restrict: 'EA',
    replace: true,
    template: ''
  };
}]);
<|endoftext|>


<commit_before>import React, { PropTypes } from 'react';
import styles from './index.module.scss';
import cssModules from 'react-css-modules';
import Menu from 'grommet/components/Menu';
import Filter from 'grommet/components/icons/base/Filter';
import List from 'grommet/components/List';
import ListItem from 'grommet/components/ListItem';

const FilterMenu = ({
  menuItems,
  onSelectItem,
  label,
  selectedItem,
}) => (
  <Menu
    icon={<Filter />}
    closeOnClick={false}
    label={label}
    className={styles.filterMenu}
    pad="medium"
  >
    <List selectable onSelect={onSelectItem} selected={selectedItem}>
      {menuItems.map((item, i) => /* eslint-disable */
        <ListItem
          key={i}
          ref={`list-item-${item.id}`}
          justify="between"
          onClick={() => onSelectItem(item.id)}
        > /* eslint-enable */
          {item.value}
        </ListItem>
      )}
    </List>
  </Menu>
);

FilterMenu.propTypes = {
  menuItems: PropTypes.array.isRequired,
  onSelectItem: PropTypes.func.isRequired,
  label: PropTypes.string.isRequired,
  selectedItem: PropTypes.object.isRequired,
};

export default cssModules(FilterMenu, styles);
<commit_msg>Feat: add filter menu styling<commit_after>import React, { PropTypes } from 'react';
import styles from './index.module.scss';
import cssModules from 'react-css-modules';
import Menu from 'grommet/components/Menu';
import Filter from 'grommet/components/icons/base/Filter';
import List from 'grommet/components/List';
import ListItem from 'grommet/components/ListItem';

const FilterMenu = ({
  menuItems,
  onSelectItem,
  label,
  selectedItem,
}) => (
  <Menu
    icon={<Filter />}
    closeOnClick={false}
    label={label}
    className={styles.filterMenu}
    pad="medium"
  >
    <List selectable onSelect={onSelectItem} selected={selectedItem}>
      {menuItems.map((item, i) => /* eslint-disable */
        <ListItem
          key={i}
          ref={`list-item-${item.id}`}
          justify="between"
          onClick={() => onSelectItem(item.id)}
        > /* eslint-enable */
          {item.value}
        </ListItem>
      )}
    </List>
  </Menu>
);

FilterMenu.propTypes = {
  menuItems: PropTypes.array.isRequired,
  onSelectItem: PropTypes.func.isRequired,
  label: PropTypes.string.isRequired,
  selectedItem: PropTypes.object,
};

export default cssModules(FilterMenu, styles);
<|endoftext|>


<commit_before>/**
 * @param {Object} $    - Global jQuery object
 * @param {Object} bolt - The Bolt module
 */
(function ($, bolt) {
    'use strict';

    /**
     * BUIC listing widget.
     *
     * @license http://opensource.org/licenses/mit-license.php MIT License
     * @author rarila
     *
     * @class buicListing
     * @memberOf jQuery.widget.bolt
     */
    $.widget('bolt.buicListing', /** @lends jQuery.widget.bolt.buicListing.prototype */ {
        /**
         * The constructor of the listing widget.
         *
         * @private
         */
        _create: function () {
            this.csrfToken  = this.element.data('bolt_csrf_token');
            this.contentType = this.element.data('contenttype');
            this.contentTypeName = this.element.data('contenttype-name');

            this.element.find('table.listing tbody').buicListingPart();
        },

        /**
         * Execute commands on triggered button.
         *
         * @param {string} action - Triggered action.
         * @param {array} ids - Array of ids to perform the action on.
         * @param {string} buttonText - Button text to be displayed on ok button.
         */
        modifyRecords: function (action, ids, buttonText) {
            var self = this,
                modifications = {},
                actions = {
                    'delete': {
                        'safe': false,
                        'name': bolt.data('recordlisting.action.delete', {'%CTNAME%': this.contentTypeName}),
                        'cmd': {'delete': null}
                    },
                    'publish': {
                        'safe': true,
                        'name': bolt.data('recordlisting.action.publish', {'%CTNAME%': this.contentTypeName}),
                        'cmd': {'modify': {'status': 'published'}}
                    },
                    'depublish': {
                        'safe': true,
                        'name': bolt.data('recordlisting.action.depublish'),
                        'cmd': {'modify': {'status': 'held'}}
                    },
                    'draft': {
                        'safe': true,
                        'name': bolt.data('recordlisting.action.draft'),
                        'cmd': {'modify': {'status': 'draft'}}
                    }
                },
                msg;

            // Build POST data.
            modifications[self.contentType] = {};
            $(ids).each(function () {
                modifications[self.contentType][this] = actions[action].cmd;
            });

            // Build message:
            if (ids.length === 1) {
                msg = bolt.data('recordlisting.confirm.one');
            } else {
                msg = bolt.data('recordlisting.confirm.multi', {'%NUMBER%': '' + ids.length + ''});
            }
            msg = msg + '

' + bolt.data('recordlisting.confirm.no-undo') + '';
            if (!actions[action].safe) {
                bootbox.dialog({
                    message: msg,
                    title: actions[action].name,
                    buttons: {
                        cancel: {
                            label: bolt.data('recordlisting.action.cancel'),
                            className: 'btn-default'
                        },
                        ok: {
                            label: buttonText,
                            className: 'btn-primary btn-danger',
                            callback: function () {
                                self._sendModifyRecordsQuery(modifications);
                            }
                        }
                    }
                });
            } else {
                self._sendModifyRecordsQuery(modifications);
            }
        },
        /**
         * Send commands to modify records.
         *
         * @param {object} modifications - The modifications to be sent.
         */
        _sendModifyRecordsQuery: function (modifications) {
            var self = this,
                url = bolt.conf('paths.async') + 'content/action' + window.location.search;
            $.ajax({
                url: url,
                type: 'POST',
                data: {
                    'bolt_csrf_token': self.csrfToken,
                    'contenttype': self.contentType,
                    'actions': modifications
                },
                success: function (data) {
                    self.element.html(data);
                    self.element.find('table.listing tbody').buicListingPart();

                    /*
                        Commented out for now - it has to be decided if functionality is wanted
                    // Restore selection state.
                    $(table).find('td input:checkbox[name="checkRow"]').each(function () {
                        var id = $(this).parents('tr').attr('id').substr(5);

                        if (id && ids.indexOf(id) >= 0) {
                            this.checked = true;
                            self._rowSelection(this);
                        }
                    });
                    $(table).find('tbody').each(function () {
                        self._handleSelectionState(this);
                    });
                    */
                },
                error: function (jqXHR, textStatus, errorThrown) {
                    console.log(jqXHR.status + ' (' + errorThrown + '):');
                    console.log(JSON.parse(jqXHR.responseText));
                },
                dataType: 'html'
            });
        }
    });
})(jQuery, Bolt);
<commit_msg>Remove 'btn-default', so there's no default action.<commit_after>/**
 * @param {Object} $    - Global jQuery object
 * @param {Object} bolt - The Bolt module
 */
(function ($, bolt) {
    'use strict';

    /**
     * BUIC listing widget.
     *
     * @license http://opensource.org/licenses/mit-license.php MIT License
     * @author rarila
     *
     * @class buicListing
     * @memberOf jQuery.widget.bolt
     */
    $.widget('bolt.buicListing', /** @lends jQuery.widget.bolt.buicListing.prototype */ {
        /**
         * The constructor of the listing widget.
         *
         * @private
         */
        _create: function () {
            this.csrfToken  = this.element.data('bolt_csrf_token');
            this.contentType = this.element.data('contenttype');
            this.contentTypeName = this.element.data('contenttype-name');

            this.element.find('table.listing tbody').buicListingPart();
        },

        /**
         * Execute commands on triggered button.
         *
         * @param {string} action - Triggered action.
         * @param {array} ids - Array of ids to perform the action on.
         * @param {string} buttonText - Button text to be displayed on ok button.
         */
        modifyRecords: function (action, ids, buttonText) {
            var self = this,
                modifications = {},
                actions = {
                    'delete': {
                        'safe': false,
                        'name': bolt.data('recordlisting.action.delete', {'%CTNAME%': this.contentTypeName}),
                        'cmd': {'delete': null}
                    },
                    'publish': {
                        'safe': true,
                        'name': bolt.data('recordlisting.action.publish', {'%CTNAME%': this.contentTypeName}),
                        'cmd': {'modify': {'status': 'published'}}
                    },
                    'depublish': {
                        'safe': true,
                        'name': bolt.data('recordlisting.action.depublish'),
                        'cmd': {'modify': {'status': 'held'}}
                    },
                    'draft': {
                        'safe': true,
                        'name': bolt.data('recordlisting.action.draft'),
                        'cmd': {'modify': {'status': 'draft'}}
                    }
                },
                msg;

            // Build POST data.
            modifications[self.contentType] = {};
            $(ids).each(function () {
                modifications[self.contentType][this] = actions[action].cmd;
            });

            // Build message:
            if (ids.length === 1) {
                msg = bolt.data('recordlisting.confirm.one');
            } else {
                msg = bolt.data('recordlisting.confirm.multi', {'%NUMBER%': '' + ids.length + ''});
            }
            msg = msg + '

' + bolt.data('recordlisting.confirm.no-undo') + '';
            if (!actions[action].safe) {
                bootbox.dialog({
                    message: msg,
                    title: actions[action].name,
                    buttons: {
                        cancel: {
                            label: bolt.data('recordlisting.action.cancel'),
                            className: 'btn-default'
                        },
                        ok: {
                            label: buttonText,
                            className: 'btn-danger',
                            callback: function () {
                                self._sendModifyRecordsQuery(modifications);
                            }
                        }
                    }
                });
            } else {
                self._sendModifyRecordsQuery(modifications);
            }
        },
        /**
         * Send commands to modify records.
         *
         * @param {object} modifications - The modifications to be sent.
         */
        _sendModifyRecordsQuery: function (modifications) {
            var self = this,
                url = bolt.conf('paths.async') + 'content/action' + window.location.search;
            $.ajax({
                url: url,
                type: 'POST',
                data: {
                    'bolt_csrf_token': self.csrfToken,
                    'contenttype': self.contentType,
                    'actions': modifications
                },
                success: function (data) {
                    self.element.html(data);
                    self.element.find('table.listing tbody').buicListingPart();

                    /*
                        Commented out for now - it has to be decided if functionality is wanted
                    // Restore selection state.
                    $(table).find('td input:checkbox[name="checkRow"]').each(function () {
                        var id = $(this).parents('tr').attr('id').substr(5);

                        if (id && ids.indexOf(id) >= 0) {
                            this.checked = true;
                            self._rowSelection(this);
                        }
                    });
                    $(table).find('tbody').each(function () {
                        self._handleSelectionState(this);
                    });
                    */
                },
                error: function (jqXHR, textStatus, errorThrown) {
                    console.log(jqXHR.status + ' (' + errorThrown + '):');
                    console.log(JSON.parse(jqXHR.responseText));
                },
                dataType: 'html'
            });
        }
    });
})(jQuery, Bolt);
<|endoftext|>


<commit_before>import transform from 'lodash/transform';
import uniq from 'lodash/uniq';
import { mapGetters } from 'vuex';
import {
  ChannelListTypes,
  fileErrors,
  ONE_B,
  ONE_KB,
  ONE_MB,
  ONE_GB,
  ONE_TB,
  filterTypes,
} from './constants';
import { createTranslator, updateTabTitle } from 'shared/i18n';
import Languages from 'shared/leUtils/Languages';
import Licenses from 'shared/leUtils/Licenses';

const sizeStrings = createTranslator('BytesForHumansStrings', {
  fileSizeInBytes: '{n, number, integer} B',
  fileSizeInKilobytes: '{n, number, integer} KB',
  fileSizeInMegabytes: '{n, number, integer} MB',
  fileSizeInGigabytes: '{n, number, integer} GB',
  fileSizeInTerabytes: '{n, number, integer} TB',
});

const stringMap = {
  [ONE_B]: 'fileSizeInBytes',
  [ONE_KB]: 'fileSizeInKilobytes',
  [ONE_MB]: 'fileSizeInMegabytes',
  [ONE_GB]: 'fileSizeInGigabytes',
  [ONE_TB]: 'fileSizeInTerabytes',
};

export default function bytesForHumans(bytes) {
  bytes = bytes || 0;
  const unit = [ONE_TB, ONE_GB, ONE_MB, ONE_KB].find(x => bytes >= x) || ONE_B;
  return sizeStrings.$tr(stringMap[unit], { n: Math.round(bytes / unit) });
}

export const fileSizeMixin = {
  methods: {
    formatFileSize(size) {
      return bytesForHumans(size);
    },
  },
};

const statusStrings = createTranslator('StatusStrings', {
  uploadFileSize: '{uploaded} of {total}',
  uploadFailedError: 'Upload failed',
  noStorageError: 'Not enough space',
});

export const fileStatusMixin = {
  mixins: [fileSizeMixin],
  computed: {
    ...mapGetters('file', ['getFileUpload']),
  },
  methods: {
    statusMessage(checksum) {
      const errorMessage = this.errorMessage(checksum);
      if (errorMessage) {
        return errorMessage;
      }
      const file = this.getFileUpload(checksum);
      if (file.total) {
        return statusStrings.$tr('uploadFileSize', {
          uploaded: bytesForHumans(file.loaded),
          total: bytesForHumans(file.total),
        });
      }
    },
    errorMessage(checksum) {
      const file = this.getFileUpload(checksum);
      if (!file) {
        return;
      }
      if (file.error === fileErrors.NO_STORAGE) {
        return statusStrings.$tr('noStorageError');
      } else if (file.error === fileErrors.UPLOAD_FAILED) {
        return statusStrings.$tr('uploadFailedError');
      }
    },
  },
};

export const constantStrings = createTranslator('ConstantStrings', {
  [ChannelListTypes.EDITABLE]: 'My channels',
  [ChannelListTypes.VIEW_ONLY]: 'View-only',
  [ChannelListTypes.PUBLIC]: 'Content library',
  [ChannelListTypes.STARRED]: 'Starred',
  do_all: '100% Correct',
  num_correct_in_a_row_10: '10 in a row',
  num_correct_in_a_row_2: '2 in a row',
  num_correct_in_a_row_3: '3 in a row',
  num_correct_in_a_row_5: '5 in a row',
  m_of_n: 'M of N...',
  do_all_description:
    'Learner must answer all questions in the exercise correctly (not recommended for long exercises)',
  num_correct_in_a_row_10_description: 'Learner must answer ten questions in a row correctly',
  num_correct_in_a_row_2_description: 'Learner must answer two questions in a row correctly',
  num_correct_in_a_row_3_description: 'Learner must answer three questions in a row correctly',
  num_correct_in_a_row_5_description: 'Learner must answer five questions in a row correctly',
  m_of_n_description:
    'Learner must answer M questions correctly from the last N questions answered (e.g. 3 out of 5 means learners need to answer 3 questions correctly out of the 5 most recently answered questions)',
  input_question: 'Input Question',
  multiple_selection: 'Multiple Selection',
  single_selection: 'Single Selection',
  perseus_question: 'Perseus Question',
  true_false: 'True/False',
  unknown_question: 'Unknown Question Type',
  mp4: 'MP4 Video',
  vtt: 'VTT Subtitle',
  mp3: 'MP3 Audio',
  pdf: 'PDF Document',
  epub: 'EPub Document',
  jpg: 'JPG Image',
  jpeg: 'JPEG Image',
  png: 'PNG Image',
  gif: 'GIF Image',
  json: 'JSON',
  svg: 'SVG Image',
  perseus: 'Perseus Exercise',
  zip: 'HTML5 Zip',
  topic: 'Topic',
  video: 'Video',
  audio: 'Audio',
  document: 'Document',
  exercise: 'Exercise',
  h5p: 'H5P App',
  html5: 'HTML5 App',
  slideshow: 'Slideshow',
  coach: 'Coaches',
  learner: 'Anyone',
  high_res_video: 'High Resolution',
  low_res_video: 'Low Resolution',
  video_subtitle: 'Subtitle',
  html5_zip: 'HTML5 Zip',
  video_thumbnail: 'Thumbnail',
  audio_thumbnail: 'Thumbnail',
  document_thumbnail: 'Thumbnail',
  exercise_thumbnail: 'Thumbnail',
  topic_thumbnail: 'Thumbnail',
  html5_thumbnail: 'Thumbnail',
  'CC BY': 'CC BY',
  'CC BY-SA': 'CC BY-SA',
  'CC BY-ND': 'CC BY-ND',
  'CC BY-NC': 'CC BY-NC',
  'CC BY-NC-SA': 'CC BY-NC-SA',
  'CC BY-NC-ND': 'CC BY-NC-ND',
  'All Rights Reserved': 'All Rights Reserved',
  'Public Domain': 'Public Domain',
  'Special Permissions': 'Special Permissions',
  'CC BY_description':
    'The Attribution License lets others distribute, remix, tweak, and build upon your work, even commercially, as long as they credit you for the original creation. This is the most accommodating of licenses offered. Recommended for maximum dissemination and use of licensed materials.',
  'CC BY-SA_description':
    'The Attribution-ShareAlike License lets others remix, tweak, and build upon your work even for commercial purposes, as long as they credit you and license their new creations under the identical terms. This license is often compared to "copyleft" free and open source software licenses. All new works based on yours will carry the same license, so any derivatives will also allow commercial use. This is the license used by Wikipedia, and is recommended for materials that would benefit from incorporating content from Wikipedia and similarly licensed projects.',
  'CC BY-ND_description':
    'The Attribution-NoDerivs License allows for redistribution, commercial and non-commercial, as long as it is passed along unchanged and in whole, with credit to you.',
  'CC BY-NC_description':
    "The Attribution-NonCommercial License lets others remix, tweak, and build upon your work non-commercially, and although their new works must also acknowledge you and be non-commercial, they don't have to license their derivative works on the same terms.",
  'CC BY-NC-SA_description':
    'The Attribution-NonCommercial-ShareAlike License lets others remix, tweak, and build upon your work non-commercially, as long as they credit you and license their new creations under the identical terms.',
  'CC BY-NC-ND_description':
    "The Attribution-NonCommercial-NoDerivs License is the most restrictive of our six main licenses, only allowing others to download your works and share them with others as long as they credit you, but they can't change them in any way or use them commercially.",
  'All Rights Reserved_description':
    'The All Rights Reserved License indicates that the copyright holder reserves, or holds for their own use, all the rights provided by copyright law under one specific copyright treaty.',
  'Public Domain_description':
    'Public Domain work has been identified as being free of known restrictions under copyright law, including all related and neighboring rights.',
  'Special Permissions_description':
    'Special Permissions is a custom license to use when the current licenses do not apply to the content. The owner of this license is responsible for creating a description of what this license entails.',

  // global copy strings
  firstCopy: 'Copy of {title}',
  nthCopy: 'Copy {n, number, integer} of {title}',
});

export const constantsTranslationMixin = {
  methods: {
    translateConstant(constant) {
      return constantStrings.$tr(constant);
    },
    translateLanguage(language) {
      return Languages.has(language) && Languages.get(language).native_name;
    },
    translateLicense(license) {
      return Licenses.has(license) && this.translateConstant(Licenses.get(license).license_name);
    },
  },
};

/**
 * jayoshih: using a mixin to handle this to handle the translations
 *           and handle cases where user opens page at a component
 */

export const routerMixin = {
  methods: {
    updateTabTitle(title) {
      updateTabTitle(title);
    },
  },
};

export const printingMixin = {
  inject: {
    printing: {
      from: 'printing',
      default: false,
    },
  },
};

export function generateSearchMixin(filterMap) {
  return {
    computed: {
      ...transform(
        filterMap,
        (result, type, key) => {
          result[key] = {
            get() {
              if (type === filterTypes.MULTISELECT) {
                return this.$route.query[key] ? this.$route.query[key].split(',') : [];
              } else if (type === filterTypes.BOOLEAN) {
                return String(this.$route.query[key]) === 'true';
              }
              return this.$route.query[key];
            },
            set(value) {
              if (type === filterTypes.MULTISELECT) {
                value.length
                  ? this.updateQueryParams({ [key]: uniq(value).join(',') })
                  : this.deleteQueryParam(key);
              } else if (type === filterTypes.BOOLEAN) {
                value ? this.updateQueryParams({ [key]: value }) : this.deleteQueryParam(key);
              } else {
                this.updateQueryParams({ [key]: value });
              }
            },
          };
        },
        {}
      ),
      filterKeys() {
        return Object.keys(filterMap).filter(k => this.$route.query[k]);
      },
    },
    methods: {
      deleteQueryParam(key) {
        let query = { ...this.$route.query };
        delete query[key];

        this.navigate(query);
      },
      updateQueryParams(params) {
        let query = {
          ...this.$route.query,
          ...params,
        };
        this.navigate(query);
      },
      clearFilters() {
        this.navigate({});
      },
      navigate(params) {
        this.$router
          .replace({
            ...this.$route,
            query: {
              ...params,
              page: 1, // Make sure we're on page 1 for every new query
            },
          })
          .catch(error => {
            if (error && error.name != 'NavigationDuplicated') {
              throw error;
            }
          });
      },
    },
  };
}
<commit_msg>no status message about the file if no errors or file<commit_after>import transform from 'lodash/transform';
import uniq from 'lodash/uniq';
import { mapGetters } from 'vuex';
import {
  ChannelListTypes,
  fileErrors,
  ONE_B,
  ONE_KB,
  ONE_MB,
  ONE_GB,
  ONE_TB,
  filterTypes,
} from './constants';
import { createTranslator, updateTabTitle } from 'shared/i18n';
import Languages from 'shared/leUtils/Languages';
import Licenses from 'shared/leUtils/Licenses';

const sizeStrings = createTranslator('BytesForHumansStrings', {
  fileSizeInBytes: '{n, number, integer} B',
  fileSizeInKilobytes: '{n, number, integer} KB',
  fileSizeInMegabytes: '{n, number, integer} MB',
  fileSizeInGigabytes: '{n, number, integer} GB',
  fileSizeInTerabytes: '{n, number, integer} TB',
});

const stringMap = {
  [ONE_B]: 'fileSizeInBytes',
  [ONE_KB]: 'fileSizeInKilobytes',
  [ONE_MB]: 'fileSizeInMegabytes',
  [ONE_GB]: 'fileSizeInGigabytes',
  [ONE_TB]: 'fileSizeInTerabytes',
};

export default function bytesForHumans(bytes) {
  bytes = bytes || 0;
  const unit = [ONE_TB, ONE_GB, ONE_MB, ONE_KB].find(x => bytes >= x) || ONE_B;
  return sizeStrings.$tr(stringMap[unit], { n: Math.round(bytes / unit) });
}

export const fileSizeMixin = {
  methods: {
    formatFileSize(size) {
      return bytesForHumans(size);
    },
  },
};

const statusStrings = createTranslator('StatusStrings', {
  uploadFileSize: '{uploaded} of {total}',
  uploadFailedError: 'Upload failed',
  noStorageError: 'Not enough space',
});

export const fileStatusMixin = {
  mixins: [fileSizeMixin],
  computed: {
    ...mapGetters('file', ['getFileUpload']),
  },
  methods: {
    statusMessage(checksum) {
      const errorMessage = this.errorMessage(checksum);
      if (errorMessage) {
        return errorMessage;
      }
      const file = this.getFileUpload(checksum);
      if (file && file.total) {
        return statusStrings.$tr('uploadFileSize', {
          uploaded: bytesForHumans(file.loaded),
          total: bytesForHumans(file.total),
        });
      }
    },
    errorMessage(checksum) {
      const file = this.getFileUpload(checksum);
      if (!file) {
        return;
      }
      if (file.error === fileErrors.NO_STORAGE) {
        return statusStrings.$tr('noStorageError');
      } else if (file.error === fileErrors.UPLOAD_FAILED) {
        return statusStrings.$tr('uploadFailedError');
      }
    },
  },
};

export const constantStrings = createTranslator('ConstantStrings', {
  [ChannelListTypes.EDITABLE]: 'My channels',
  [ChannelListTypes.VIEW_ONLY]: 'View-only',
  [ChannelListTypes.PUBLIC]: 'Content library',
  [ChannelListTypes.STARRED]: 'Starred',
  do_all: '100% Correct',
  num_correct_in_a_row_10: '10 in a row',
  num_correct_in_a_row_2: '2 in a row',
  num_correct_in_a_row_3: '3 in a row',
  num_correct_in_a_row_5: '5 in a row',
  m_of_n: 'M of N...',
  do_all_description:
    'Learner must answer all questions in the exercise correctly (not recommended for long exercises)',
  num_correct_in_a_row_10_description: 'Learner must answer ten questions in a row correctly',
  num_correct_in_a_row_2_description: 'Learner must answer two questions in a row correctly',
  num_correct_in_a_row_3_description: 'Learner must answer three questions in a row correctly',
  num_correct_in_a_row_5_description: 'Learner must answer five questions in a row correctly',
  m_of_n_description:
    'Learner must answer M questions correctly from the last N questions answered (e.g. 3 out of 5 means learners need to answer 3 questions correctly out of the 5 most recently answered questions)',
  input_question: 'Input Question',
  multiple_selection: 'Multiple Selection',
  single_selection: 'Single Selection',
  perseus_question: 'Perseus Question',
  true_false: 'True/False',
  unknown_question: 'Unknown Question Type',
  mp4: 'MP4 Video',
  vtt: 'VTT Subtitle',
  mp3: 'MP3 Audio',
  pdf: 'PDF Document',
  epub: 'EPub Document',
  jpg: 'JPG Image',
  jpeg: 'JPEG Image',
  png: 'PNG Image',
  gif: 'GIF Image',
  json: 'JSON',
  svg: 'SVG Image',
  perseus: 'Perseus Exercise',
  zip: 'HTML5 Zip',
  topic: 'Topic',
  video: 'Video',
  audio: 'Audio',
  document: 'Document',
  exercise: 'Exercise',
  h5p: 'H5P App',
  html5: 'HTML5 App',
  slideshow: 'Slideshow',
  coach: 'Coaches',
  learner: 'Anyone',
  high_res_video: 'High Resolution',
  low_res_video: 'Low Resolution',
  video_subtitle: 'Subtitle',
  html5_zip: 'HTML5 Zip',
  video_thumbnail: 'Thumbnail',
  audio_thumbnail: 'Thumbnail',
  document_thumbnail: 'Thumbnail',
  exercise_thumbnail: 'Thumbnail',
  topic_thumbnail: 'Thumbnail',
  html5_thumbnail: 'Thumbnail',
  'CC BY': 'CC BY',
  'CC BY-SA': 'CC BY-SA',
  'CC BY-ND': 'CC BY-ND',
  'CC BY-NC': 'CC BY-NC',
  'CC BY-NC-SA': 'CC BY-NC-SA',
  'CC BY-NC-ND': 'CC BY-NC-ND',
  'All Rights Reserved': 'All Rights Reserved',
  'Public Domain': 'Public Domain',
  'Special Permissions': 'Special Permissions',
  'CC BY_description':
    'The Attribution License lets others distribute, remix, tweak, and build upon your work, even commercially, as long as they credit you for the original creation. This is the most accommodating of licenses offered. Recommended for maximum dissemination and use of licensed materials.',
  'CC BY-SA_description':
    'The Attribution-ShareAlike License lets others remix, tweak, and build upon your work even for commercial purposes, as long as they credit you and license their new creations under the identical terms. This license is often compared to "copyleft" free and open source software licenses. All new works based on yours will carry the same license, so any derivatives will also allow commercial use. This is the license used by Wikipedia, and is recommended for materials that would benefit from incorporating content from Wikipedia and similarly licensed projects.',
  'CC BY-ND_description':
    'The Attribution-NoDerivs License allows for redistribution, commercial and non-commercial, as long as it is passed along unchanged and in whole, with credit to you.',
  'CC BY-NC_description':
    "The Attribution-NonCommercial License lets others remix, tweak, and build upon your work non-commercially, and although their new works must also acknowledge you and be non-commercial, they don't have to license their derivative works on the same terms.",
  'CC BY-NC-SA_description':
    'The Attribution-NonCommercial-ShareAlike License lets others remix, tweak, and build upon your work non-commercially, as long as they credit you and license their new creations under the identical terms.',
  'CC BY-NC-ND_description':
    "The Attribution-NonCommercial-NoDerivs License is the most restrictive of our six main licenses, only allowing others to download your works and share them with others as long as they credit you, but they can't change them in any way or use them commercially.",
  'All Rights Reserved_description':
    'The All Rights Reserved License indicates that the copyright holder reserves, or holds for their own use, all the rights provided by copyright law under one specific copyright treaty.',
  'Public Domain_description':
    'Public Domain work has been identified as being free of known restrictions under copyright law, including all related and neighboring rights.',
  'Special Permissions_description':
    'Special Permissions is a custom license to use when the current licenses do not apply to the content. The owner of this license is responsible for creating a description of what this license entails.',

  // global copy strings
  firstCopy: 'Copy of {title}',
  nthCopy: 'Copy {n, number, integer} of {title}',
});

export const constantsTranslationMixin = {
  methods: {
    translateConstant(constant) {
      return constantStrings.$tr(constant);
    },
    translateLanguage(language) {
      return Languages.has(language) && Languages.get(language).native_name;
    },
    translateLicense(license) {
      return Licenses.has(license) && this.translateConstant(Licenses.get(license).license_name);
    },
  },
};

/**
 * jayoshih: using a mixin to handle this to handle the translations
 *           and handle cases where user opens page at a component
 */

export const routerMixin = {
  methods: {
    updateTabTitle(title) {
      updateTabTitle(title);
    },
  },
};

export const printingMixin = {
  inject: {
    printing: {
      from: 'printing',
      default: false,
    },
  },
};

export function generateSearchMixin(filterMap) {
  return {
    computed: {
      ...transform(
        filterMap,
        (result, type, key) => {
          result[key] = {
            get() {
              if (type === filterTypes.MULTISELECT) {
                return this.$route.query[key] ? this.$route.query[key].split(',') : [];
              } else if (type === filterTypes.BOOLEAN) {
                return String(this.$route.query[key]) === 'true';
              }
              return this.$route.query[key];
            },
            set(value) {
              if (type === filterTypes.MULTISELECT) {
                value.length
                  ? this.updateQueryParams({ [key]: uniq(value).join(',') })
                  : this.deleteQueryParam(key);
              } else if (type === filterTypes.BOOLEAN) {
                value ? this.updateQueryParams({ [key]: value }) : this.deleteQueryParam(key);
              } else {
                this.updateQueryParams({ [key]: value });
              }
            },
          };
        },
        {}
      ),
      filterKeys() {
        return Object.keys(filterMap).filter(k => this.$route.query[k]);
      },
    },
    methods: {
      deleteQueryParam(key) {
        let query = { ...this.$route.query };
        delete query[key];

        this.navigate(query);
      },
      updateQueryParams(params) {
        let query = {
          ...this.$route.query,
          ...params,
        };
        this.navigate(query);
      },
      clearFilters() {
        this.navigate({});
      },
      navigate(params) {
        this.$router
          .replace({
            ...this.$route,
            query: {
              ...params,
              page: 1, // Make sure we're on page 1 for every new query
            },
          })
          .catch(error => {
            if (error && error.name != 'NavigationDuplicated') {
              throw error;
            }
          });
      },
    },
  };
}
<|endoftext|>


<commit_before>
const _ = require('lodash');

window.$ = window.jQuery = require('jquery');
require('./libs/jquery-ui');
require('./libs/timepicker');

const Vue = require('vue');
const VueRouter = require('vue-router');
const Vuex = require('vuex');

Vue.use(VueRouter);
Vue.use(Vuex);

const axios = require('axios');
//const fullCalendar = require('fullcalendar');
const moment = require('moment');

const io = require('socket.io-client');

if (window.location.hostname.indexOf('gamestats.brentwood.bc.ca') != -1) {
    window.socket = io('//' + window.location.hostname);
} else {
    window.socket = io('//' + window.location.hostname + ':3000');
}

Vue.prototype.$http = axios;

Vue.component('feedback', require('./components/Feedback.vue'));
Vue.component('app-menu', require('./components/Menu.vue'));
Vue.component('autocomplete', require('./components/AutoComplete.vue'));
Vue.component('scoreboard', require('./components/Scoreboard.vue'));
Vue.component('room-list', require('./components/RoomList.vue'));
Vue.component('team-game-stats', require('./components/TeamGameStats.vue'));
Vue.component('team-game-chart', require('./components/TeamGameChart.vue'));
Vue.component('team-game-report', require('./components/TeamGameReport.vue'));
Vue.component('team-games-list', require('./components/TeamGamesList.vue'));
Vue.component('team-stat-setting', require('./components/TeamStatSetting.vue'));
Vue.component('team-players-stats-report', require('./components/TeamPlayersStatsReport.vue'));
Vue.component('team-players-list', require('./components/TeamPlayersList.vue'));
Vue.component('player-game-stat', require('./components/PlayerGameStat.vue'));
Vue.component('player-game-report', require('./components/PlayerGameReport.vue'));

const router = new VueRouter({
    mode: 'history',
    routes: [
        { path: '/login', component: require('./components/Login.vue') },
        { path: '/home', component: require('./components/Home.vue') },
        { path: '/select-team', component: require('./components/SelectTeam.vue') },

        { path: '/my-account', component: require('./components/User.vue') },
        { path: '/users', component: require('./components/Users.vue') },
        { path: '/users/:id', component: require('./components/User.vue') },
        { path: '/users/create', component: require('./components/User.vue') },

        { path: '/teams', component: require('./components/Teams.vue') },
        { path: '/teams/:id', component: require('./components/Team.vue') },
        { path: '/teams/create', component: require('./components/Team.vue') },
        { path: '/teams/games/:id', component: require('./components/TeamGames.vue') },
        { path: '/teams/players/:id', component: require('./components/TeamPlayers.vue') },

        { path: '/games', component: require('./components/Games.vue') },
        { path: '/games/:id', component: require('./components/Game.vue') },
        { path: '/games/create', component: require('./components/Game.vue') },
        { path: '/games/stats/:id', component: require('./components/GameStats.vue') },

        { path: '/players/stats/:id', component: require('./components/PlayerStatsReport.vue') },

        { path: '/stats', component: require('./components/Stats.vue') },
        { path: '/stats/:id', component: require('./components/Stat.vue') },
        { path: '/stats/create', component: require('./components/Stat.vue') },

        //{ path: '/not-found', component: require('./components/404.vue') },
        //{ path: '/*', redirect: '/not-found' }
    ]
});

router.beforeEach( function(to, from, next) {
    if (to.path != '/login') {
        if (store.state.user.authenticated) {

            store.dispatch('clearErrorsFeedback');

            if (to.path == '/select-team') {
                next();
            } else if (!store.state.activeTeam.id) {
                next('/select-team');
            } else {
                next();
            }

        } else {
            if (to.path != '/') {
                store.dispatch('addFeedback', {'type': 'error', 'message': 'Please login to acces that page'});
            }
            store.state.intended = to.path;
            next('/login');
        }
    } else {
        if (store.state.user.authenticated) {
            next('/home');
        } else {
            next();
        }
    }
});

const store = new Vuex.Store({
    state: {

        user: {
            authenticated: false,
            token: '',
            first_name: '',
            last_name: '',
            email: '',
            id: '',
            roles: []
        },

        feedback: [],
        intended: '',
        menu: [],
        activeTeam: {}
    },

    getters: {
        user_name: state => {
            return state.user.first_name + ' ' + state.user.last_name;
        }
    },

    mutations: {

        setActiveTeam (state, team) {
            state.activeTeam = team;
        },

        removeActiveTeam (state) {
            state.activeTeam = {};
        },

        setToken (state, token) {
            state.user.authenticated = true;
            state.user.token = token;
        },

        removeToken (state) {
            state.user.authenticated = false;
            state.user.token = '';
            clearInterval(window.loginCheck);
        },

        addFeedback (state, item) {
            state.feedback.push(item);
        },

        clearFeedback (state) {
            state.feedback = state.feedback.filter( function(item) {
                //console.log(new Date().getTime() + '::' + item.expire);
                let now = new Date().getTime();
                if (item.expire < now && item.type != 'error') {
                    return false;
                } else {
                    return true;
                }
            });
        },

        clearErrorsFeedback (state) {
            state.feedback = state.feedback.filter( function(item) {
                return item.type != 'error';
            });
        },

        userInfo (state, info) {
            state.user.first_name = info.first_name;
            state.user.last_name = info.last_name;
            state.user.email = info.email;
            state.user.id = info.id;
            state.user.roles = info.roles;
        },

        /*
        userRoles (state, info) {
            state.user.roles = info;
        },
        */

        menu (state, menu) {
            state.menu = menu;
        }

    },

    actions: {

        setActiveTeam({ commit, state }, team) {

            if (state.activeTeam.id != team.id) {
                if (state.activeTeam.id) {
                    window.socket.emit('leave-room', 'team.' + state.activeTeam.id);
                }
                window.socket.emit('join-room', 'team.' + team.id);
            }
            commit('setActiveTeam', team);
        },

        removeActiveTeam({ commit, state }) {
            commit('removeActiveTeam');
        },

        setToken({ commit, state }, token) {

            commit('setToken', token);

            // connect incase we had logged out before
            window.socket.connect();

            // authenticate our token
            window.socket.emit('authenticate', {token: token});

            window.loginCheck = setInterval(function() { app.loginCheck() }, 10000);
        },

        userRoles({ commit, state }, info) {
            commit('userRoles', info);
            app.$store.dispatch('addFeedback', {'type': 'info', 'message': 'Your groups have been loaded'});
            if (app.userHasRole('admin')) {
                window.socket.emit('join-room', 'auth.info');
            }
        },

        userInfo({ commit, state }, info) {
            commit('userInfo', info);
        },

        removeToken({ commit, state }) {
            commit('removeToken');
            clearInterval(window.loginCheck);
        },

        addFeedback({ commit, state }, feedback) {

            let item = {
                type: feedback.type,
                message: feedback.message,
                link: feedback.link,
                expire: (new Date().getTime() + 4900)
            };
            commit('addFeedback', item);

            // clear out any info and successes automatically

            setTimeout(function() {
               app.$store.dispatch('clearFeedback');
            }, 5000);

        },

        clearFeedback({ commit }) {
            commit('clearFeedback');
        },

        clearErrorsFeedback({ commit }) {
            commit('clearErrorsFeedback');
        },

        menu({ commit, state }, menu) {
            commit('menu', menu);
            app.$store.dispatch('addFeedback', {'type': 'info', 'message': 'Your menu is ready'});
        }

    }
});

import UserMixins from './components/UserMixins'
import Helpers from './components/Helpers'

const app = new Vue({
    el: '#app',
    router,
    store,

    mixins: [UserMixins, Helpers],

    methods: {

        logout: function(e){

            var vue = this;
            vue.$http.post(e.target.action).then( function(response) {

                window.socket.emit('auth.info', store.getters.user_name + ' has disconnected');

                // call the action for the store update
                vue.$store.dispatch('removeToken').then( function() {
                    window.socket.close();
                });

                vue.$store.dispatch('addFeedback', {'type': 'success', 'message': 'Logged Out'});
                vue.$store.dispatch('removeActiveTeam');
                vue.$router.push('/login');

            }, function(error) {
                // we have timed out or our token is invalid so lets go to the login page
                vue.$router.push('/login');
            });

        },

        loginCheck: function() {

            var vue = this;

            vue.$http.post('/api/login-check').then( function(response) {

                if (response.data.status == 'timeout') {
                    vue.timeout();
                }

            }, function(error) {

                vue.timeout();

            });

        },

        timeout: function() {

            var vue = this;

            vue.$store.dispatch('removeToken').then( function() {
                window.socket.close();
            });

            vue.$store.dispatch('addFeedback', {'type': 'error', 'message': 'Your session has timed out'});
            vue.$store.dispatch('removeActiveTeam');
            vue.$router.push('/login');

        }

    },

    created: function () {

        var vue = this;

        if (!vue.$store.state.user.authenticated) {
            vue.$router.push('/login');
        } else {
            vue.$router.push('/home');
        }

        window.socket.on('public.info', function (data) {
            vue.$store.dispatch('addFeedback', {'type': 'info', 'message': data});
        });

        window.socket.on('auth.info', function (data) {
            app.$store.dispatch('addFeedback', {'type': 'info', 'message': data});
        }.bind(app));

        /**
         *  Socket Events
         *  we use the laravel class as the event to listen for
         */

        // User Events

        window.socket.on('App\\Events\\UserUpdated', function (data) {

            vue.$store.dispatch('addFeedback', {'type': 'announcement', 'message': data.message});

            vue.$http.post('/api/users/my-info').then( function(response) {
                vue.$store.dispatch('userInfo', response.data);
            }, function(error) {

            });

        });

        /*
        window.socket.on('App\\Events\\UserRolesUpdated', function (data) {

            vue.$store.dispatch('addFeedback', {'type': 'announcement', 'message': data.message});

            vue.$http.post('/api/users/my-roles').then( function(response) {
                vue.$store.dispatch('userRoles', response.data);
            }, function(error) {
                vue.$store.dispatch('addFeedback', {'type': 'error', 'message': 'There was an error loading your groups'});
            });

        });
        */

        window.socket.on('App\\Events\\AuthAnnouncement', function (data) {
            vue.$store.dispatch('addFeedback', {'type': 'announcement', 'message': data.message});
        });

        window.socket.on('App\\Events\\UserCreated', function (data) {
            vue.$store.dispatch('addFeedback', {'type': 'announcement', 'message': data.message});
        });

        window.socket.on('App\\Events\\UserRemoved', function (data) {
            vue.$store.dispatch('addFeedback', {'type': 'announcement', 'message': data.message});
        });

        // Team Events

        window.socket.on('App\\Events\\TeamCreated', function (data) {
            vue.$store.dispatch('addFeedback', {'type': 'announcement', 'message': data.message});
        });

        window.socket.on('App\\Events\\TeamRemoved', function (data) {
            vue.$store.dispatch('addFeedback', {'type': 'announcement', 'message': data.message});
        });

        // Game Events

        window.socket.on('App\\Events\\GameCreated', function (data) {
            vue.$store.dispatch('addFeedback', {'type': 'announcement', 'message': data.message, 'link': data.link});
        });

        window.socket.on('App\\Events\\GameRemoved', function (data) {
            vue.$store.dispatch('addFeedback', {'type': 'announcement', 'message': data.message});
        });

        // Room Events
        window.socket.on('room-info', function (data) {
            vue.$store.dispatch('addFeedback', {'type': 'announcement', 'message': data});
        });
    }

});

/*
window.axios.interceptors.request.use(function (config) {
    // Do something before request is sent
    app.showLoading();
    return config;
  }, function (error) {
    // Do something with request error
    return Promise.reject(error);
  });

window.axios.interceptors.response.use(function (response) {
    // Do something with response data
    app.hideLoading();
    return response;
  }, function (error) {
    // Do something with response error
    return Promise.reject(error);
  });
*/

google.charts.load('current', {'packages':['corechart']});

var supportsTouch = 'ontouchstart' in window || navigator.msMaxTouchPoints;

$(function(){

    /**
     * Date Time Picker using jQuery UI
     */

	$(document).on('focus', 'input.datepicker', function(){
		$(this).datepicker({
			dateFormat: 'yy-mm-dd',
			showAnim: 'slideDown',
            changeMonth: true,
            changeYear: true,
		});
	});

	$(document).on('focus', 'input.datetimepicker', function(){

		$(this).datetimepicker({
			dateFormat: 'yy-mm-dd',
			showAnim: 'slideDown',
			stepMinute: 5,
            changeMonth: true,
            changeYear: true,
		});
	});

	$(document).on('focus', 'input.timepicker', function() {
		$(this).timepicker({
			showAnim: 'slideDown',
			stepMinute: 5
		});
	});

    /**
     * A little Jquery to set css vars for windows size
     * may be able to ditch all this if we dont need
     * window size
     */

    setWidth();

	$(window).resize(function() {
		if (supportsTouch) {
			window.addEventListener('orientationchange', orientation_change, false);
		} else {
            setWidth();
		}
	});

});

function orientation_change() {
	setWidth();
}

function setWidth() {
    document.documentElement.style.setProperty('--screen-width', $(window).width() + 'px');
}
<commit_msg>increased timeout check to 1min<commit_after>
const _ = require('lodash');

window.$ = window.jQuery = require('jquery');
require('./libs/jquery-ui');
require('./libs/timepicker');

const Vue = require('vue');
const VueRouter = require('vue-router');
const Vuex = require('vuex');

Vue.use(VueRouter);
Vue.use(Vuex);

const axios = require('axios');
//const fullCalendar = require('fullcalendar');
const moment = require('moment');

const io = require('socket.io-client');

if (window.location.hostname.indexOf('gamestats.brentwood.bc.ca') != -1) {
    window.socket = io('//' + window.location.hostname);
} else {
    window.socket = io('//' + window.location.hostname + ':3000');
}

Vue.prototype.$http = axios;

Vue.component('feedback', require('./components/Feedback.vue'));
Vue.component('app-menu', require('./components/Menu.vue'));
Vue.component('autocomplete', require('./components/AutoComplete.vue'));
Vue.component('scoreboard', require('./components/Scoreboard.vue'));
Vue.component('room-list', require('./components/RoomList.vue'));
Vue.component('team-game-stats', require('./components/TeamGameStats.vue'));
Vue.component('team-game-chart', require('./components/TeamGameChart.vue'));
Vue.component('team-game-report', require('./components/TeamGameReport.vue'));
Vue.component('team-games-list', require('./components/TeamGamesList.vue'));
Vue.component('team-stat-setting', require('./components/TeamStatSetting.vue'));
Vue.component('team-players-stats-report', require('./components/TeamPlayersStatsReport.vue'));
Vue.component('team-players-list', require('./components/TeamPlayersList.vue'));
Vue.component('player-game-stat', require('./components/PlayerGameStat.vue'));
Vue.component('player-game-report', require('./components/PlayerGameReport.vue'));

const router = new VueRouter({
    mode: 'history',
    routes: [
        { path: '/login', component: require('./components/Login.vue') },
        { path: '/home', component: require('./components/Home.vue') },
        { path: '/select-team', component: require('./components/SelectTeam.vue') },

        { path: '/my-account', component: require('./components/User.vue') },
        { path: '/users', component: require('./components/Users.vue') },
        { path: '/users/:id', component: require('./components/User.vue') },
        { path: '/users/create', component: require('./components/User.vue') },

        { path: '/teams', component: require('./components/Teams.vue') },
        { path: '/teams/:id', component: require('./components/Team.vue') },
        { path: '/teams/create', component: require('./components/Team.vue') },
        { path: '/teams/games/:id', component: require('./components/TeamGames.vue') },
        { path: '/teams/players/:id', component: require('./components/TeamPlayers.vue') },

        { path: '/games', component: require('./components/Games.vue') },
        { path: '/games/:id', component: require('./components/Game.vue') },
        { path: '/games/create', component: require('./components/Game.vue') },
        { path: '/games/stats/:id', component: require('./components/GameStats.vue') },

        { path: '/players/stats/:id', component: require('./components/PlayerStatsReport.vue') },

        { path: '/stats', component: require('./components/Stats.vue') },
        { path: '/stats/:id', component: require('./components/Stat.vue') },
        { path: '/stats/create', component: require('./components/Stat.vue') },

        //{ path: '/not-found', component: require('./components/404.vue') },
        //{ path: '/*', redirect: '/not-found' }
    ]
});

router.beforeEach( function(to, from, next) {
    if (to.path != '/login') {
        if (store.state.user.authenticated) {

            store.dispatch('clearErrorsFeedback');

            if (to.path == '/select-team') {
                next();
            } else if (!store.state.activeTeam.id) {
                next('/select-team');
            } else {
                next();
            }

        } else {
            if (to.path != '/') {
                store.dispatch('addFeedback', {'type': 'error', 'message': 'Please login to acces that page'});
            }
            store.state.intended = to.path;
            next('/login');
        }
    } else {
        if (store.state.user.authenticated) {
            next('/home');
        } else {
            next();
        }
    }
});

const store = new Vuex.Store({
    state: {

        user: {
            authenticated: false,
            token: '',
            first_name: '',
            last_name: '',
            email: '',
            id: '',
            roles: []
        },

        feedback: [],
        intended: '',
        menu: [],
        activeTeam: {}
    },

    getters: {
        user_name: state => {
            return state.user.first_name + ' ' + state.user.last_name;
        }
    },

    mutations: {

        setActiveTeam (state, team) {
            state.activeTeam = team;
        },

        removeActiveTeam (state) {
            state.activeTeam = {};
        },

        setToken (state, token) {
            state.user.authenticated = true;
            state.user.token = token;
        },

        removeToken (state) {
            state.user.authenticated = false;
            state.user.token = '';
            clearInterval(window.loginCheck);
        },

        addFeedback (state, item) {
            state.feedback.push(item);
        },

        clearFeedback (state) {
            state.feedback = state.feedback.filter( function(item) {
                //console.log(new Date().getTime() + '::' + item.expire);
                let now = new Date().getTime();
                if (item.expire < now && item.type != 'error') {
                    return false;
                } else {
                    return true;
                }
            });
        },

        clearErrorsFeedback (state) {
            state.feedback = state.feedback.filter( function(item) {
                return item.type != 'error';
            });
        },

        userInfo (state, info) {
            state.user.first_name = info.first_name;
            state.user.last_name = info.last_name;
            state.user.email = info.email;
            state.user.id = info.id;
            state.user.roles = info.roles;
        },

        /*
        userRoles (state, info) {
            state.user.roles = info;
        },
        */

        menu (state, menu) {
            state.menu = menu;
        }

    },

    actions: {

        setActiveTeam({ commit, state }, team) {

            if (state.activeTeam.id != team.id) {
                if (state.activeTeam.id) {
                    window.socket.emit('leave-room', 'team.' + state.activeTeam.id);
                }
                window.socket.emit('join-room', 'team.' + team.id);
            }
            commit('setActiveTeam', team);
        },

        removeActiveTeam({ commit, state }) {
            commit('removeActiveTeam');
        },

        setToken({ commit, state }, token) {

            commit('setToken', token);

            // connect incase we had logged out before
            window.socket.connect();

            // authenticate our token
            window.socket.emit('authenticate', {token: token});

            window.loginCheck = setInterval(function() { app.loginCheck() }, 60000);
        },

        userRoles({ commit, state }, info) {
            commit('userRoles', info);
            app.$store.dispatch('addFeedback', {'type': 'info', 'message': 'Your groups have been loaded'});
            if (app.userHasRole('admin')) {
                window.socket.emit('join-room', 'auth.info');
            }
        },

        userInfo({ commit, state }, info) {
            commit('userInfo', info);
        },

        removeToken({ commit, state }) {
            commit('removeToken');
            clearInterval(window.loginCheck);
        },

        addFeedback({ commit, state }, feedback) {

            let item = {
                type: feedback.type,
                message: feedback.message,
                link: feedback.link,
                expire: (new Date().getTime() + 4900)
            };
            commit('addFeedback', item);

            // clear out any info and successes automatically

            setTimeout(function() {
               app.$store.dispatch('clearFeedback');
            }, 5000);

        },

        clearFeedback({ commit }) {
            commit('clearFeedback');
        },

        clearErrorsFeedback({ commit }) {
            commit('clearErrorsFeedback');
        },

        menu({ commit, state }, menu) {
            commit('menu', menu);
            app.$store.dispatch('addFeedback', {'type': 'info', 'message': 'Your menu is ready'});
        }

    }
});

import UserMixins from './components/UserMixins'
import Helpers from './components/Helpers'

const app = new Vue({
    el: '#app',
    router,
    store,

    mixins: [UserMixins, Helpers],

    methods: {

        logout: function(e){

            var vue = this;
            vue.$http.post(e.target.action).then( function(response) {

                window.socket.emit('auth.info', store.getters.user_name + ' has disconnected');

                // call the action for the store update
                vue.$store.dispatch('removeToken').then( function() {
                    window.socket.close();
                });

                vue.$store.dispatch('addFeedback', {'type': 'success', 'message': 'Logged Out'});
                vue.$store.dispatch('removeActiveTeam');
                vue.$router.push('/login');

            }, function(error) {
                // we have timed out or our token is invalid so lets go to the login page
                vue.$router.push('/login');
            });

        },

        loginCheck: function() {

            var vue = this;

            vue.$http.post('/api/login-check').then( function(response) {

                if (response.data.status == 'timeout') {
                    vue.timeout();
                }

            }, function(error) {

                vue.timeout();

            });

        },

        timeout: function() {

            var vue = this;

            vue.$store.dispatch('removeToken').then( function() {
                window.socket.close();
            });

            vue.$store.dispatch('addFeedback', {'type': 'error', 'message': 'Your session has timed out'});
            vue.$store.dispatch('removeActiveTeam');
            vue.$router.push('/login');

        }

    },

    created: function () {

        var vue = this;

        if (!vue.$store.state.user.authenticated) {
            vue.$router.push('/login');
        } else {
            vue.$router.push('/home');
        }

        window.socket.on('public.info', function (data) {
            vue.$store.dispatch('addFeedback', {'type': 'info', 'message': data});
        });

        window.socket.on('auth.info', function (data) {
            app.$store.dispatch('addFeedback', {'type': 'info', 'message': data});
        }.bind(app));

        /**
         *  Socket Events
         *  we use the laravel class as the event to listen for
         */

        // User Events

        window.socket.on('App\\Events\\UserUpdated', function (data) {

            vue.$store.dispatch('addFeedback', {'type': 'announcement', 'message': data.message});

            vue.$http.post('/api/users/my-info').then( function(response) {
                vue.$store.dispatch('userInfo', response.data);
            }, function(error) {

            });

        });

        /*
        window.socket.on('App\\Events\\UserRolesUpdated', function (data) {

            vue.$store.dispatch('addFeedback', {'type': 'announcement', 'message': data.message});

            vue.$http.post('/api/users/my-roles').then( function(response) {
                vue.$store.dispatch('userRoles', response.data);
            }, function(error) {
                vue.$store.dispatch('addFeedback', {'type': 'error', 'message': 'There was an error loading your groups'});
            });

        });
        */

        window.socket.on('App\\Events\\AuthAnnouncement', function (data) {
            vue.$store.dispatch('addFeedback', {'type': 'announcement', 'message': data.message});
        });

        window.socket.on('App\\Events\\UserCreated', function (data) {
            vue.$store.dispatch('addFeedback', {'type': 'announcement', 'message': data.message});
        });

        window.socket.on('App\\Events\\UserRemoved', function (data) {
            vue.$store.dispatch('addFeedback', {'type': 'announcement', 'message': data.message});
        });

        // Team Events

        window.socket.on('App\\Events\\TeamCreated', function (data) {
            vue.$store.dispatch('addFeedback', {'type': 'announcement', 'message': data.message});
        });

        window.socket.on('App\\Events\\TeamRemoved', function (data) {
            vue.$store.dispatch('addFeedback', {'type': 'announcement', 'message': data.message});
        });

        // Game Events

        window.socket.on('App\\Events\\GameCreated', function (data) {
            vue.$store.dispatch('addFeedback', {'type': 'announcement', 'message': data.message, 'link': data.link});
        });

        window.socket.on('App\\Events\\GameRemoved', function (data) {
            vue.$store.dispatch('addFeedback', {'type': 'announcement', 'message': data.message});
        });

        // Room Events
        window.socket.on('room-info', function (data) {
            vue.$store.dispatch('addFeedback', {'type': 'announcement', 'message': data});
        });
    }

});

/*
window.axios.interceptors.request.use(function (config) {
    // Do something before request is sent
    app.showLoading();
    return config;
  }, function (error) {
    // Do something with request error
    return Promise.reject(error);
  });

window.axios.interceptors.response.use(function (response) {
    // Do something with response data
    app.hideLoading();
    return response;
  }, function (error) {
    // Do something with response error
    return Promise.reject(error);
  });
*/

google.charts.load('current', {'packages':['corechart']});

var supportsTouch = 'ontouchstart' in window || navigator.msMaxTouchPoints;

$(function(){

    /**
     * Date Time Picker using jQuery UI
     */

	$(document).on('focus', 'input.datepicker', function(){
		$(this).datepicker({
			dateFormat: 'yy-mm-dd',
			showAnim: 'slideDown',
            changeMonth: true,
            changeYear: true,
		});
	});

	$(document).on('focus', 'input.datetimepicker', function(){

		$(this).datetimepicker({
			dateFormat: 'yy-mm-dd',
			showAnim: 'slideDown',
			stepMinute: 5,
            changeMonth: true,
            changeYear: true,
		});
	});

	$(document).on('focus', 'input.timepicker', function() {
		$(this).timepicker({
			showAnim: 'slideDown',
			stepMinute: 5
		});
	});

    /**
     * A little Jquery to set css vars for windows size
     * may be able to ditch all this if we dont need
     * window size
     */

    setWidth();

	$(window).resize(function() {
		if (supportsTouch) {
			window.addEventListener('orientationchange', orientation_change, false);
		} else {
            setWidth();
		}
	});

});

function orientation_change() {
	setWidth();
}

function setWidth() {
    document.documentElement.style.setProperty('--screen-width', $(window).width() + 'px');
}
<|endoftext|>


<commit_before>import Vue from 'vue';
import VueResource from 'vue-resource';

Vue.use(VueResource);

import Project from './components/Project.vue';
import FormError from './components/FormError.vue';

Vue.http.headers.common['X-CSRF-TOKEN'] = document.querySelector('#token').getAttribute('value');

new Vue({
	el: '#project',

	components: {
		Project,
		FormError,
	},

	data: {
		projects: [],

		newProject: {
			title: '',
			url: '',
			repo_url: '',
			short: '',
			description: ''
		},

		formSubmitted: false,

		errors: [],
	},

	ready: function() {
		this.fetchProjects();
	},

	methods: {
		fetchProjects(page_url) {
			page_url = page_url || '/api/projects';

			this.$http.get(page_url).then(function(response) {
				this.$set('projects', response.data);
			});
		},

		createProject() {
			let project = this.newProject;

			this.$set('projects', project);

			this.$http.post('api/projects', project).then(function(response) {
				this.newProject = {
					title: '',
					projectUrl: '',
					repoUrl: '',
					short: '',
					description: ''
				};

				this.formSubmitted = true;
			}, function (response) {
				this.$set('errors', response.data);
			});
		}
	},
});
<commit_msg>removed unused js file<commit_after><|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// Domain Sample
// pref("extensions.switch-link-external-handler@clear-code.com.ie.patterns.0", "http://*.microsoft.com");
// pref("extensions.switch-link-external-handler@clear-code.com.ie.patterns.1", "https://*.microsoft.com");
// This entry should be ingored because lower priority.
// pref("extensions.switch-link-external-handler@clear-code.com.ie.patterns.2", "https://*.mozilla.org");
// pref("extensions.switch-link-external-handler@clear-code.com.ie.patterns.3", "http://groonga.org");
// pref("extensions.switch-link-external-handler@clear-code.com.chrome.patterns.0", "https://*.clear-code.com");
// pref("extensions.switch-link-external-handler@clear-code.com.chrome.patterns.1", "https://github.com");
// pref("extensions.switch-link-external-handler@clear-code.com.chrome.patterns.2", "http://?.hatena.ne.jp");
// pref("extensions.switch-link-external-handler@clear-code.com.chrome.patterns.3", "http://groonga.org");
// Priority Sample
// pref("extensions.switch-link-external-handler@clear-code.com.chrome.priority", 50);
// pref("extensions.switch-link-external-handler@clear-code.com.ie.priority", 20);
<commit_msg>Fix supplementary commen position<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// Domain Sample
// pref("extensions.switch-link-external-handler@clear-code.com.ie.patterns.0", "http://*.microsoft.com");
// pref("extensions.switch-link-external-handler@clear-code.com.ie.patterns.1", "https://*.microsoft.com");
// pref("extensions.switch-link-external-handler@clear-code.com.ie.patterns.2", "https://*.mozilla.org");
// This entry should be ingored because lower priority.
// pref("extensions.switch-link-external-handler@clear-code.com.ie.patterns.3", "http://groonga.org");
// pref("extensions.switch-link-external-handler@clear-code.com.chrome.patterns.0", "https://*.clear-code.com");
// pref("extensions.switch-link-external-handler@clear-code.com.chrome.patterns.1", "https://github.com");
// pref("extensions.switch-link-external-handler@clear-code.com.chrome.patterns.2", "http://?.hatena.ne.jp");
// pref("extensions.switch-link-external-handler@clear-code.com.chrome.patterns.3", "http://groonga.org");
// Priority Sample
// pref("extensions.switch-link-external-handler@clear-code.com.chrome.priority", 50);
// pref("extensions.switch-link-external-handler@clear-code.com.ie.priority", 20);
<|endoftext|>