<commit_before>/**
 * @author Serhii Maksymchuk from Ubrainians for imCode
 * 15.08.18
 */
define(
    'imcms-tinymce-text-editor',
    [
        'tinymce', 'jquery', 'imcms', 'imcms-text-editor-utils', 'imcms-text-history-plugin',
        'imcms-text-validation-plugin', 'imcms-image-in-text-plugin', 'imcms-text-discard-changes-plugin',
        'imcms-text-full-screen-plugin', 'imcms-switch-to-plain-text-plugin', 'imcms-switch-to-html-mode-plugin',
        'imcms-switch-to-text-editor-plugin', 'imcms-html-filtering-policy-plugin'
    ],
    function (
        tinyMCE, $, imcms, textEditorUtils, textHistory, textValidation, imageInText, discardChangesPlugin,
        fullScreenPlugin, switchToPlainTextPlugin, switchToHtmlModePlugin, switchToTextEditorPlugin,
        htmlFilteringPolicyPlugin
    ) {

        require('tinymce/themes/modern/theme');
        require('tinymce/plugins/autolink');
        require('tinymce/plugins/link');
        require('tinymce/plugins/lists');
        require('tinymce/plugins/hr');
        require('tinymce/plugins/code');
        require('tinymce/plugins/save');
        require('tinymce/plugins/fullscreen');

        const sourceCodePlugin = 'code';
        const fontPlugins = ['bold', 'italic', 'underline'].join(' ');
        const listsPlugins = ['bullist', 'numlist'].join(' ');
        const horizontalLinePlugin = 'hr';
        const textAlignPlugins = ['alignleft', 'aligncenter', 'alignright', 'alignjustify'].join(' ');
        const specialInsertsPlugins = ['link', imageInText.pluginName].join(' ');
        const customImcmsTextPlugins = [textHistory.pluginName, textValidation.pluginName].join(' ');
        const fullscreenPlugin = fullScreenPlugin.pluginName;
        const saveAndDiscardPlugins = ['save', discardChangesPlugin.pluginName].join(' ');
        const switchModePlugins = [
            switchToPlainTextPlugin.pluginName,
            switchToHtmlModePlugin.pluginName,
            switchToTextEditorPlugin.pluginName
        ].join(' ');
        const htmlFilteringPolicyPlugins = htmlFilteringPolicyPlugin.pluginName;

        const toolbar = [
            sourceCodePlugin,
            fontPlugins,
            listsPlugins,
            horizontalLinePlugin,
            textAlignPlugins,
            specialInsertsPlugins,
            customImcmsTextPlugins,
            fullscreenPlugin,
            saveAndDiscardPlugins,
            switchModePlugins,
            htmlFilteringPolicyPlugins
        ].join(' | ');

        const inlineEditorConfig = {
            skin_url: imcms.contextPath + '/imcms/css/tinymce/skins/white',
            convert_urls: false,
            cache_suffix: '?v=0.0.1',
            branding: false,
            skin: 'white',
            inline: true,
            inline_boundaries: false,
            toolbar_items_size: 'small',
            content_css: imcms.contextPath + '/imcms/css/imcms-text_editor.css',
            menubar: false,
            statusbar: false,
            force_br_newlines: false,
            force_p_newlines: true,
            forced_root_block: false,
            init_instance_callback: prepareEditor,
            save_onsavecallback: textEditorUtils.saveContent,
            setup: editor => {
                textHistory.initTextHistory(editor);
                textValidation.initTextValidation(editor);
                fullScreenPlugin.initFullScreen(editor);
                imageInText.initImageInText(editor);
                discardChangesPlugin.initDiscardChanges(editor);
                switchToPlainTextPlugin.initSwitchToPlainText(editor);
                switchToHtmlModePlugin.initSwitchToHtmlMode(editor);
                switchToTextEditorPlugin.initSwitchToTextEditor(editor);
                htmlFilteringPolicyPlugin.initHtmlFilteringPolicy(editor);
            },
            valid_elements: '*[*]',
            plugins: ['autolink link lists hr code ' + fullScreenPlugin.pluginName + ' save'],
            toolbar: toolbar
        };

        function clearSaveBtnText(editor) {
            delete editor.buttons.save.text;
        }

        function setEditorFocusOnEditControlClick(editor) {
            editor.$().parents('.imcms-editor-area--text')
                .find('.imcms-control--text')
                .on('click', () => {
                    editor.focus();
                });
        }

        function initSaveContentConfirmation(editor) {
            editor.on('blur', () => {
                textEditorUtils.onEditorBlur(editor);
            });
        }

        function prepareEditor(editor) {
            clearSaveBtnText(editor);
            textEditorUtils.setEditorFocus(editor);
            setEditorFocusOnEditControlClick(editor);
            textEditorUtils.showEditButton($(editor.$()));
            initSaveContentConfirmation(editor);
        }

        return {
            init: $textEditor => {
                const textAreaId = $textEditor.attr('id');
                const toolbarId = $textEditor.closest('.imcms-editor-area--text')
                    .find('.imcms-editor-area__text-toolbar')
                    .attr('id');

                const editorConfig = $.extend({
                    selector: '#' + textAreaId,
                    fixed_toolbar_container: '#' + toolbarId
                }, inlineEditorConfig);

                // 4.5.7 the last version compatible with IE 10
                if (imcms.browserInfo.isIE10) {
                    tinyMCE.baseURL = 'https://cdnjs.cloudflare.com/ajax/libs/tinymce/4.5.7';
                    tinyMCE.suffix = '.min';
                }

                return tinyMCE.init(editorConfig);
            }
        };
    }
);
<commit_msg>Issue IMCMS-483: Improve the text-editor - Add formats;<commit_after>/**
 * @author Serhii Maksymchuk from Ubrainians for imCode
 * 15.08.18
 */
define(
    'imcms-tinymce-text-editor',
    [
        'tinymce', 'jquery', 'imcms', 'imcms-text-editor-utils', 'imcms-text-history-plugin',
        'imcms-text-validation-plugin', 'imcms-image-in-text-plugin', 'imcms-text-discard-changes-plugin',
        'imcms-text-full-screen-plugin', 'imcms-switch-to-plain-text-plugin', 'imcms-switch-to-html-mode-plugin',
        'imcms-switch-to-text-editor-plugin', 'imcms-html-filtering-policy-plugin'
    ],
    function (
        tinyMCE, $, imcms, textEditorUtils, textHistory, textValidation, imageInText, discardChangesPlugin,
        fullScreenPlugin, switchToPlainTextPlugin, switchToHtmlModePlugin, switchToTextEditorPlugin,
        htmlFilteringPolicyPlugin
    ) {

        require('tinymce/themes/modern/theme');
        require('tinymce/plugins/autolink');
        require('tinymce/plugins/link');
        require('tinymce/plugins/lists');
        require('tinymce/plugins/hr');
        require('tinymce/plugins/code');
        require('tinymce/plugins/save');
        require('tinymce/plugins/fullscreen');

        const sourceCodePlugin = 'code';
        const fontPlugins = ['bold', 'italic', 'underline', 'styleselect'].join(' ');
        const listsPlugins = ['bullist', 'numlist'].join(' ');
        const horizontalLinePlugin = 'hr';
        const textAlignPlugins = ['alignleft', 'aligncenter', 'alignright', 'alignjustify'].join(' ');
        const specialInsertsPlugins = ['link', imageInText.pluginName].join(' ');
        const customImcmsTextPlugins = [textHistory.pluginName, textValidation.pluginName].join(' ');
        const fullscreenPlugin = fullScreenPlugin.pluginName;
        const saveAndDiscardPlugins = ['save', discardChangesPlugin.pluginName].join(' ');
        const switchModePlugins = [
            switchToPlainTextPlugin.pluginName,
            switchToHtmlModePlugin.pluginName,
            switchToTextEditorPlugin.pluginName
        ].join(' ');
        const htmlFilteringPolicyPlugins = htmlFilteringPolicyPlugin.pluginName;

        const toolbar = [
            sourceCodePlugin,
            fontPlugins,
            listsPlugins,
            horizontalLinePlugin,
            textAlignPlugins,
            specialInsertsPlugins,
            customImcmsTextPlugins,
            fullscreenPlugin,
            saveAndDiscardPlugins,
            switchModePlugins,
            htmlFilteringPolicyPlugins
        ].join(' | ');

        const styleFormats = [
            {title: 'Heading 2', block: 'h2'},
            {title: 'Heading 3', block: 'h3'},
            {title: 'Heading 4', block: 'h4'},
            {title: 'Heading 5', block: 'h5'},
            {title: 'Heading 6', block: 'h6'},
            {title: 'Normal', block: 'p'},
        ];

        const inlineEditorConfig = {
            skin_url: imcms.contextPath + '/imcms/css/tinymce/skins/white',
            convert_urls: false,
            cache_suffix: '?v=0.0.1',
            branding: false,
            skin: 'white',
            inline: true,
            inline_boundaries: false,
            toolbar_items_size: 'small',
            content_css: imcms.contextPath + '/imcms/css/imcms-text_editor.css',
            menubar: false,
            statusbar: false,
            force_br_newlines: false,
            force_p_newlines: true,
            forced_root_block: false,
            init_instance_callback: prepareEditor,
            save_onsavecallback: textEditorUtils.saveContent,
            setup: editor => {
                textHistory.initTextHistory(editor);
                textValidation.initTextValidation(editor);
                fullScreenPlugin.initFullScreen(editor);
                imageInText.initImageInText(editor);
                discardChangesPlugin.initDiscardChanges(editor);
                switchToPlainTextPlugin.initSwitchToPlainText(editor);
                switchToHtmlModePlugin.initSwitchToHtmlMode(editor);
                switchToTextEditorPlugin.initSwitchToTextEditor(editor);
                htmlFilteringPolicyPlugin.initHtmlFilteringPolicy(editor);
            },
            valid_elements: '*[*]',
            plugins: ['autolink link lists hr code ' + fullScreenPlugin.pluginName + ' save'],
            toolbar: toolbar,
            style_formats: styleFormats,
        };

        function clearSaveBtnText(editor) {
            delete editor.buttons.save.text;
        }

        function setEditorFocusOnEditControlClick(editor) {
            editor.$().parents('.imcms-editor-area--text')
                .find('.imcms-control--text')
                .on('click', () => {
                    editor.focus();
                });
        }

        function initSaveContentConfirmation(editor) {
            editor.on('blur', () => {
                textEditorUtils.onEditorBlur(editor);
            });
        }

        function prepareEditor(editor) {
            clearSaveBtnText(editor);
            textEditorUtils.setEditorFocus(editor);
            setEditorFocusOnEditControlClick(editor);
            textEditorUtils.showEditButton($(editor.$()));
            initSaveContentConfirmation(editor);
        }

        return {
            init: $textEditor => {
                const textAreaId = $textEditor.attr('id');
                const toolbarId = $textEditor.closest('.imcms-editor-area--text')
                    .find('.imcms-editor-area__text-toolbar')
                    .attr('id');

                const editorConfig = $.extend({
                    selector: '#' + textAreaId,
                    fixed_toolbar_container: '#' + toolbarId
                }, inlineEditorConfig);

                // 4.5.7 the last version compatible with IE 10
                if (imcms.browserInfo.isIE10) {
                    tinyMCE.baseURL = 'https://cdnjs.cloudflare.com/ajax/libs/tinymce/4.5.7';
                    tinyMCE.suffix = '.min';
                }

                return tinyMCE.init(editorConfig);
            }
        };
    }
);
<|endoftext|>


<commit_before>/**
 * Created by Dmytro Zemlianskyi from Ubrainians for imCode
 * 14.09.19.
 */
define("imcms-standalone-editor-toolbar-builder",
    [
        "imcms-bem-builder", "imcms-components-builder", "jquery", "imcms", "imcms-events", "imcms-languages-rest-api",
    ],
    function (BEM, componentsBuilder, $, imcms, events, languagesRestApi) {

        let $panelContainer, $panel;

        function flagOnClick() {
            const languageCode = $(this).text();

            if (languageCode !== imcms.language.code) {
                languagesRestApi.replace({code: languageCode}).done(function () {
                    location.reload(true);
                });
            }
        }

        function buildFlags() {
            return componentsBuilder.flags.flagsContainer(function (language) {
                return ["<div>", {
                    text: language.code,
                    click: flagOnClick
                }];
            });
        }

        function createToolbarPanel() {
            const adminPanelBEM = new BEM({
                block: "imcms-editor-toolbar-panel",
                elements: {
                    "id": "",
                    "no": "",
                    "label": ""
                }
            });

            const $tag = $(".imcms-editor-area");

            const $id = adminPanelBEM.buildBlockElement("id", "<div>", {
                text: $tag.attr("data-doc-id"),
                title: "docId"
            });
            const $idItem = $("<div>").append($id);

            const $no = adminPanelBEM.buildBlockElement("no", "<div>", {
                text: $tag.attr("data-index"),
                title: "data index"
            });
            const $noItem = $("<div>").append($no);

            const $flagsItem = buildFlags();
            // var $buttonsContainer = buildPanelButtons(opts);

            const adminPanelElements$ = [
                $idItem,
                $noItem,
                $flagsItem,
                // $buttonsContainer
            ];

            const panelAttributes = {
                id: "imcms-editor-toolbar-panel",
            };
            return $panel = adminPanelBEM.buildBlock("<div>", adminPanelElements$, panelAttributes, "item");

        }

        return {
            buildPanel: () => {
                if ($panelContainer) {
                    return;
                }

                $panelContainer = $("<div>", {
                    "id": "imcms-editor-toolbar",
                    "class": "imcms-editor-toolbar",
                    html: createToolbarPanel()
                });

                console.log(imcms);

                $("body")
                    .addClass("standalone-editor-body")
                    .prepend($panelContainer);

            }
        }
    }
);
<commit_msg>IMCMS-375 - Details in top panel: - Fix documentation comment<commit_after>/**
 * Created by Dmytro Zemlianskyi from Ubrainians for imCode
 * 14.09.18.
 */
define("imcms-standalone-editor-toolbar-builder",
    [
        "imcms-bem-builder", "imcms-components-builder", "jquery", "imcms", "imcms-events", "imcms-languages-rest-api",
    ],
    function (BEM, componentsBuilder, $, imcms, events, languagesRestApi) {

        let $panelContainer, $panel;

        function flagOnClick() {
            const languageCode = $(this).text();

            if (languageCode !== imcms.language.code) {
                languagesRestApi.replace({code: languageCode}).done(function () {
                    location.reload(true);
                });
            }
        }

        function buildFlags() {
            return componentsBuilder.flags.flagsContainer(function (language) {
                return ["<div>", {
                    text: language.code,
                    click: flagOnClick
                }];
            });
        }

        function createToolbarPanel() {
            const adminPanelBEM = new BEM({
                block: "imcms-editor-toolbar-panel",
                elements: {
                    "id": "",
                    "no": "",
                    "label": ""
                }
            });

            const $tag = $(".imcms-editor-area");

            const $id = adminPanelBEM.buildBlockElement("id", "<div>", {
                text: $tag.attr("data-doc-id"),
                title: "docId"
            });
            const $idItem = $("<div>").append($id);

            const $no = adminPanelBEM.buildBlockElement("no", "<div>", {
                text: $tag.attr("data-index"),
                title: "data index"
            });
            const $noItem = $("<div>").append($no);

            const $flagsItem = buildFlags();
            // var $buttonsContainer = buildPanelButtons(opts);

            const adminPanelElements$ = [
                $idItem,
                $noItem,
                $flagsItem,
                // $buttonsContainer
            ];

            const panelAttributes = {
                id: "imcms-editor-toolbar-panel",
            };
            return $panel = adminPanelBEM.buildBlock("<div>", adminPanelElements$, panelAttributes, "item");

        }

        return {
            buildPanel: () => {
                if ($panelContainer) {
                    return;
                }

                $panelContainer = $("<div>", {
                    "id": "imcms-editor-toolbar",
                    "class": "imcms-editor-toolbar",
                    html: createToolbarPanel()
                });

                console.log(imcms);

                $("body")
                    .addClass("standalone-editor-body")
                    .prepend($panelContainer);

            }
        }
    }
);
<|endoftext|>


<commit_before>function clearTabContent(tab) {
    const content = tab;
    content.innerText = '';
}

function getJSON(url, callback) {
    const xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);
    xhr.responseType = 'json';
    xhr.onload = () => {
        const status = xhr.status;
        if (status === 200) {
            callback(null, xhr.response);
        } else {
            callback(status);
        }
    };
    xhr.send(null);
}

function insertVideo(title, videoLink) {
    const container = document.createElement('div');
    container.className = 'video-window';

    const videoTitle = document.createElement('span');
    videoTitle.innerText = title;
    videoTitle.className = 'product-title';
    container.appendChild(videoTitle);

    const videoWindow = document.createElement('iframe');
    videoWindow.className = 'youtube';
    videoWindow.src = videoLink;
    container.appendChild(videoWindow);

    return container;
}

const videoTabContent = document.querySelector('#Videos');

if (videoTabContent) {
    let tabContent = videoTabContent.innerText.split('.')[1];
    tabContent = tabContent.split('%%')[0];
    console.log('this is tabcontent', tabContent);
    const requestURL = 'https://www.aqlightinggroup.com/content/json/video-tab-videos.json';

    getJSON(requestURL, (error, data) => {
        if (error) {
            // console.log('This is the error', error);
        } else {
            console.log('THIS IS DATA', data);
            for (let i = data.length - 1; i >= 0; i--) {
                if (data[i].name === tabContent) {
                    clearTabContent(videoTabContent);
                    const newContent = insertVideo(data[i].title, data[i].url);
                    videoTabContent.appendChild(newContent);
                }
            }
        }
    });

    // if (tabContent) {
    //     switch (tabContent) {
    //     case 'LEDRopeVideos': {
    //         clearTabContent(videoTabContent);
    //         const newContent = insertVideo('DIY Video Guide: LED Rope Light', 'https://www.youtube.com/embed/yf7B4UgraXg?list=PLNsL1D_GAczZ_0Ocddeic0uivx1u3lWPP');
    //         videoTabContent.appendChild(newContent);
    //         break;
    //     }
    //     case 'PGC3BVideos': {
    //         clearTabContent(videoTabContent);
    //         const newContent = insertVideo('DIY Video Guide: PGC3B', 'https://www.youtube.com/embed/-paZ8wrVQLY?rel=0');
    //         videoTabContent.appendChild(newContent);
    //         break;
    //     }
    //     default: {
    //         clearTabContent(videoTabContent);
    //         videoTabContent.innerText = 'Coming Soon!';
    //         break;
    //     }
    //     }
    // }
}
<commit_msg>Removed Console logs<commit_after>function clearTabContent(tab) {
    const content = tab;
    content.innerText = '';
}

function getJSON(url, callback) {
    const xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);
    xhr.responseType = 'json';
    xhr.onload = () => {
        const status = xhr.status;
        if (status === 200) {
            callback(null, xhr.response);
        } else {
            callback(status);
        }
    };
    xhr.send(null);
}

function insertVideo(title, videoLink) {
    const container = document.createElement('div');
    container.className = 'video-window';

    const videoTitle = document.createElement('span');
    videoTitle.innerText = title;
    videoTitle.className = 'product-title';
    container.appendChild(videoTitle);

    const videoWindow = document.createElement('iframe');
    videoWindow.className = 'youtube';
    videoWindow.src = videoLink;
    container.appendChild(videoWindow);

    return container;
}

const videoTabContent = document.querySelector('#Videos');

if (videoTabContent) {
    let tabContent = videoTabContent.innerText.split('.')[1];
    tabContent = tabContent.split('%%')[0];
    const requestURL = 'https://www.aqlightinggroup.com/content/json/video-tab-videos.json';

    getJSON(requestURL, (error, data) => {
        if (error) {
            // console.log('This is the error', error);
        } else {
            for (let i = data.length - 1; i >= 0; i--) {
                if (data[i].name === tabContent) {
                    clearTabContent(videoTabContent);
                    const newContent = insertVideo(data[i].title, data[i].url);
                    videoTabContent.appendChild(newContent);
                }
            }
        }
    });

    // if (tabContent) {
    //     switch (tabContent) {
    //     case 'LEDRopeVideos': {
    //         clearTabContent(videoTabContent);
    //         const newContent = insertVideo('DIY Video Guide: LED Rope Light', 'https://www.youtube.com/embed/yf7B4UgraXg?list=PLNsL1D_GAczZ_0Ocddeic0uivx1u3lWPP');
    //         videoTabContent.appendChild(newContent);
    //         break;
    //     }
    //     case 'PGC3BVideos': {
    //         clearTabContent(videoTabContent);
    //         const newContent = insertVideo('DIY Video Guide: PGC3B', 'https://www.youtube.com/embed/-paZ8wrVQLY?rel=0');
    //         videoTabContent.appendChild(newContent);
    //         break;
    //     }
    //     default: {
    //         clearTabContent(videoTabContent);
    //         videoTabContent.innerText = 'Coming Soon!';
    //         break;
    //     }
    //     }
    // }
}
<|endoftext|>


<commit_before>var $ = require('jquery');
var _ = require('underscore');
var Backbone = require('backbone');

describe('components/form-components/editors/slider', function () {
  var labels = ['Huckepack', 'Naseweis', 'Packe', 'Pick', 'Puck', 'Purzelbaum', 'Rumpelbold'];
  var values = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];

  var createViewFn = function (options) {
    var defaultOptions = {
      labels: labels,
      schema: {}
    };

    var view = new Backbone.Form.editors.Slider(_.extend(defaultOptions, options));
    view.render();
    return view;
  };

  beforeEach(function () {
    this.view = createViewFn();
    this.viewWithValues = createViewFn({
      values: values,
      value: 'f'
    });

    this.view.render();
    this.viewWithValues.render();
  });

  describe('render', function () {
    it('should render properly', function () {
      expect(this.view.$('.js-slider').length).toBe(1);
      expect(this.view.$('.js-tick').length).toBe(labels.length);
      expect(this.view.$('.js-label').text()).toBe('Huckepack');
      expect($(this.view.$('.js-tick').get(0)).hasClass('is-highlighted')).toBeTruthy();

      expect(this.viewWithValues.$('.js-slider').length).toBe(1);
      expect(this.viewWithValues.$('.js-tick').length).toBe(labels.length);
      expect(this.viewWithValues.$('.js-label').text()).toBe('Purzelbaum');
      expect($(this.viewWithValues.$('.js-tick').get(5)).hasClass('is-highlighted')).toBeTruthy();
    });

    it('should display neither the ticks nor the slider when there is only one value', function () {
      this.view._values = ['1'];
      this.view.render();
      expect(this.view.$('.js-slider').css('display')).toBe('none');
      expect(this.view.$('.js-ticks').css('display')).toBe('none');
    });
  });

  describe('data', function () {
    it('should get a value by default', function () {
      expect(this.view.$('.js-label').text()).toBe('Huckepack');
      expect(this.viewWithValues.$('.js-label').text()).toBe('Purzelbaum');
    });

    describe('change value', function () {
      beforeEach(function () {
        this.onChanged = jasmine.createSpy('onChanged');
        this.view.bind('change', this.onChanged);
        this.viewWithValues.bind('change', this.onChanged);
      });

      describe('when slider changes', function () {
        beforeEach(function () {
          var $slider = this.view.$('.js-slider');
          $slider.val(4).change();
          var $sliderWithValues = this.viewWithValues.$('.js-slider');
          $sliderWithValues.val(4).change();
        });

        it('should trigger change', function () {
          expect(this.onChanged).toHaveBeenCalled();
        });

        it('should update label', function () {
          expect(this.view.$('.js-label').text()).toBe('Puck');
          expect(this.viewWithValues.$('.js-label').text()).toBe('Puck');
        });

        it('should highlight tick', function () {
          expect($(this.view.$('.js-tick').get(4)).hasClass('is-highlighted')).toBeTruthy();
          expect($(this.viewWithValues.$('.js-tick').get(4)).hasClass('is-highlighted')).toBeTruthy();
        });

        it('should return value', function () {
          expect(this.view.getValue()).toBe(4);
          expect(this.viewWithValues.getValue()).toBe('e');
        });
      });
    });

    describe('initial selection', function () {
      it('should start selecting the lowest value by default', function () {
        this.view = createViewFn({
          values: [1, 2, 3, 4],
          labels: ['a', 'b', 'c', 'd'],
          schema: {}
        });

        expect(this.view.getValue()).toBe(1);
      });

      it('should accept option to start selecting the highest value', function () {
        this.view = createViewFn({
          values: [1, 2, 3, 4],
          labels: ['a', 'b', 'c', 'd'],
          initial: 'highest',
          schema: {}
        });

        expect(this.view.getValue()).toBe(4);
      });
    });

    describe('exceptions', function () {
      it('should throw exception when the values and labels differ', function () {
        var wrapper = function () {
          createViewFn({
            values: [1, 2, 3, 4],
            labels: ['a', 'b'],
            schema: {}
          });
        };
        expect(wrapper).toThrow();
      });

      it('should throw exception when there are no labels', function () {
        var wrapper = function () {
          createViewFn({
            values: [1, 2, 3, 4],
            schema: {}
          });
        };
        expect(wrapper).toThrow();
      });
    });

    it('should destroy horizontal slider when element is removed', function () {
      spyOn(this.view, '_destroySlider');
      this.view.remove();
      expect(this.view._destroySlider).toHaveBeenCalled();
    });
  });

  afterEach(function () {
    this.view.remove();
    this.viewWithValues.remove();
  });
});
<commit_msg>Fix specs.<commit_after>var $ = require('jquery');
var _ = require('underscore');
var Backbone = require('backbone');

describe('components/form-components/editors/slider', function () {
  var labels = ['Huckepack', 'Naseweis', 'Packe', 'Pick', 'Puck', 'Purzelbaum', 'Rumpelbold'];
  var values = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];

  var createViewFn = function (options) {
    var defaultOptions = {
      labels: labels,
      schema: {}
    };

    var view = new Backbone.Form.editors.Slider(_.extend(defaultOptions, options));
    view.render();
    return view;
  };

  beforeEach(function () {
    this.view = createViewFn();
    this.viewWithValues = createViewFn({
      values: values,
      value: 'f'
    });

    this.view.render();
    this.viewWithValues.render();
  });

  describe('render', function () {
    it('should render properly', function () {
      expect(this.view.$('.js-slider').length).toBe(1);
      expect(this.view.$('.js-tick').length).toBe(labels.length);
      expect(this.view.$('.js-label').text()).toBe('Huckepack');
      expect($(this.view.$('.js-tick').get(0)).hasClass('is-highlighted')).toBeTruthy();

      expect(this.viewWithValues.$('.js-slider').length).toBe(1);
      expect(this.viewWithValues.$('.js-tick').length).toBe(labels.length);
      expect(this.viewWithValues.$('.js-label').text()).toBe('Purzelbaum');
      expect($(this.viewWithValues.$('.js-tick').get(5)).hasClass('is-highlighted')).toBeTruthy();
    });

    it('should display neither the ticks nor the slider when there is only one value', function (done) {
      var self = this;
      this.view._values = ['1'];

      document.body.appendChild(this.view.el);
      this.view.render();

      setTimeout(function () {
        expect(self.view.$('.js-slider').css('display')).toBe('none');
        expect(self.view.$('.js-ticks').css('display')).toBe('none');
        done();
      }, 0);
    });
  });

  describe('data', function () {
    it('should get a value by default', function () {
      expect(this.view.$('.js-label').text()).toBe('Huckepack');
      expect(this.viewWithValues.$('.js-label').text()).toBe('Purzelbaum');
    });

    describe('change value', function () {
      beforeEach(function () {
        this.onChanged = jasmine.createSpy('onChanged');
        this.view.bind('change', this.onChanged);
        this.viewWithValues.bind('change', this.onChanged);
      });

      describe('when slider changes', function () {
        beforeEach(function () {
          var $slider = this.view.$('.js-slider');
          $slider.val(4).change();
          var $sliderWithValues = this.viewWithValues.$('.js-slider');
          $sliderWithValues.val(4).change();
        });

        it('should trigger change', function () {
          expect(this.onChanged).toHaveBeenCalled();
        });

        it('should update label', function () {
          expect(this.view.$('.js-label').text()).toBe('Puck');
          expect(this.viewWithValues.$('.js-label').text()).toBe('Puck');
        });

        it('should highlight tick', function () {
          expect($(this.view.$('.js-tick').get(4)).hasClass('is-highlighted')).toBeTruthy();
          expect($(this.viewWithValues.$('.js-tick').get(4)).hasClass('is-highlighted')).toBeTruthy();
        });

        it('should return value', function () {
          expect(this.view.getValue()).toBe(4);
          expect(this.viewWithValues.getValue()).toBe('e');
        });
      });
    });

    describe('initial selection', function () {
      it('should start selecting the lowest value by default', function () {
        this.view = createViewFn({
          values: [1, 2, 3, 4],
          labels: ['a', 'b', 'c', 'd'],
          schema: {}
        });

        expect(this.view.getValue()).toBe(1);
      });

      it('should accept option to start selecting the highest value', function () {
        this.view = createViewFn({
          values: [1, 2, 3, 4],
          labels: ['a', 'b', 'c', 'd'],
          initial: 'highest',
          schema: {}
        });

        expect(this.view.getValue()).toBe(4);
      });
    });

    describe('exceptions', function () {
      it('should throw exception when the values and labels differ', function () {
        var wrapper = function () {
          createViewFn({
            values: [1, 2, 3, 4],
            labels: ['a', 'b'],
            schema: {}
          });
        };
        expect(wrapper).toThrow();
      });

      it('should throw exception when there are no labels', function () {
        var wrapper = function () {
          createViewFn({
            values: [1, 2, 3, 4],
            schema: {}
          });
        };
        expect(wrapper).toThrow();
      });
    });

    it('should destroy horizontal slider when element is removed', function () {
      spyOn(this.view, '_destroySlider');
      this.view.remove();
      expect(this.view._destroySlider).toHaveBeenCalled();
    });
  });

  afterEach(function () {
    this.view.remove();
    this.viewWithValues.remove();
  });
});
<|endoftext|>


<commit_before>var _ = require('underscore');
var Backbone = require('backbone');
var cdb = require('cartodb.js');
var ColumnMergeModel = require('./column_merge/column_merge_model');
var SpatialMergeModel = require('./spatial_merge/spatial_merge_model');

/**
 * View model for merge datasets view.
 */
module.exports = cdb.core.Model.extend({

  defaults: {
    mergeFlavors: undefined, // Collection, created with model
    prevSteps: [],
    currentStep: undefined,
    table: undefined,
    excludeColumns: [
      'cartodb_id',
      'created_at',
      'updated_at',
      'the_geom_webmercator',
      'cartodb_georef_status'
    ]
  },

  initialize: function(attrs) {
    if (!attrs.table) throw new Error('table is required');
    this.elder('initialize');

    this.set('mergeFlavors', new Backbone.Collection([
      new ColumnMergeModel({
        table: this.get('table'),
        excludeColumns: this.get('excludeColumns')
      }),
      new SpatialMergeModel()
    ]));
  },

  allSteps: function() {
    var steps = [];

    var currentStep = this.get('currentStep');
    var firstStep = this.get('prevSteps')[0] || currentStep;
    if (firstStep) {
      var Model = firstStep.constructor;
      while (Model) {
        steps.push(
          _.extend({
            isCurrent: Model === currentStep.constructor
          }, Model.header)
        );
        Model = Model.nextStep;
      }
    }

    return steps;
  },

  isLastStep: function() {
    var currentStep = this.get('currentStep');
    return !(currentStep && currentStep.constructor.nextStep);
  },

  gotoNextStep: function() {
    if (this.isLastStep()) return;

    var currentStep = this.get('currentStep');
    var nextStep = currentStep.nextStep();
    this.set({
      prevSteps: this.get('prevSteps').concat(currentStep),
      currentStep: nextStep
    });
  },

  gotoPrevStep: function() {
    this.set('currentStep', this.get('prevSteps').pop());
  },

  merge: function(callbacks) {
    // TODO: extract actual merge from the view, for now fake error
    setTimeout(callbacks.error, 1000);
  }

});
<commit_msg>Add missing piece for merge<commit_after>var _ = require('underscore');
var $ = require('jquery');
var Backbone = require('backbone');
var cdb = require('cartodb.js');
var ColumnMergeModel = require('./column_merge/column_merge_model');
var SpatialMergeModel = require('./spatial_merge/spatial_merge_model');

/**
 * View model for merge datasets view.
 */
module.exports = cdb.core.Model.extend({

  defaults: {
    mergeFlavors: undefined, // Collection, created with model
    prevSteps: [],
    currentStep: undefined,
    table: undefined,
    excludeColumns: [
      'cartodb_id',
      'created_at',
      'updated_at',
      'the_geom_webmercator',
      'cartodb_georef_status'
    ]
  },

  initialize: function(attrs) {
    if (!attrs.table) throw new Error('table is required');
    this.elder('initialize');

    this.set('mergeFlavors', new Backbone.Collection([
      new ColumnMergeModel({
        table: this.get('table'),
        excludeColumns: this.get('excludeColumns')
      }),
      new SpatialMergeModel()
    ]));
  },

  allSteps: function() {
    var steps = [];

    var currentStep = this.get('currentStep');
    var firstStep = this.get('prevSteps')[0] || currentStep;
    if (firstStep) {
      var Model = firstStep.constructor;
      while (Model) {
        steps.push(
          _.extend({
            isCurrent: Model === currentStep.constructor
          }, Model.header)
        );
        Model = Model.nextStep;
      }
    }

    return steps;
  },

  isLastStep: function() {
    var currentStep = this.get('currentStep');
    return !(currentStep && currentStep.constructor.nextStep);
  },

  gotoNextStep: function() {
    if (this.isLastStep()) return;

    var currentStep = this.get('currentStep');
    var nextStep = currentStep.nextStep();
    this.set({
      prevSteps: this.get('prevSteps').concat(currentStep),
      currentStep: nextStep
    });
  },

  gotoPrevStep: function() {
    this.set('currentStep', this.get('prevSteps').pop());
  },

  merge: function(callbacks) {
    // TODO: taken from old code, cdb.admin.MergeTableDialog.merge
    //   could this be done in a better way?
    var data = {
      table_name: this.get('table').get('name') + '_merge',
      sql: this.get('currentStep').generateSQLQuery()
    };

    $.ajax({
      type: 'POST',
      url: cdb.config.prefixUrl() + '/api/v1/imports',
      data: data,
      success: callbacks.success,
      error: callbacks.error
    });
  }

});
<|endoftext|>


<commit_before><commit_msg>Updated Scene.js<commit_after>EZ3.Scene = function() {
  EZ3.Entity.call(this);
};

EZ3.Scene.prototype = Object.create(EZ3.Entity.prototype);
EZ3.Scene.prototype.constructor = EZ3.Scene;
<|endoftext|>


<commit_before>/**
 * @fileoverview
 * Object representing a Scratch Comment (block or workspace).
 */

const uid = require('../util/uid');
const Cast = require('../util/cast');

class Comment {
    /**
     * @param {string} id Id of the comment.
     * @param {string} text Text content of the comment.
     * @param {number} x X position of the comment on the workspace.
     * @param {number} y Y position of the comment on the workspace.
     * @param {number} width The width of the comment when it is full size.
     * @param {number} height The height of the comment when it is full size.
     * @param {boolean} minimized Whether the comment is minimized.
     * @constructor
     */
    constructor (id, text, x, y, width, height, minimized) {
        this.id = id || uid();
        this.text = text;
        this.x = x;
        this.y = y;
        this.width = Math.max(Cast.toNumber(width), Comment.MIN_WIDTH);
        this.height = Math.max(Cast.toNumber(height), Comment.MIN_HEIGHT);
        this.minimized = minimized || false;
        this.blockId = null;
    }

    toXML () {
        return `<comment id="${this.id}" x="${this.x}" y="${
            this.y}" w="${this.width}" h="${this.height}" pinned="${
            this.blockId !== null}" minimized="${this.minimized}">${this.text}</comment>`;
    }

    // TODO choose min and defaults for width and height
    static get MIN_WIDTH () {
        return 20;
    }

    static get MIN_HEIGHT () {
        return 20;
    }

    static get DEFAULT_WIDTH () {
        return 100;
    }

    static get DEFAULT_HEIGHT () {
        return 100;
    }

}

module.exports = Comment;
<commit_msg>XML escape comment text.<commit_after>/**
 * @fileoverview
 * Object representing a Scratch Comment (block or workspace).
 */

const uid = require('../util/uid');
const Cast = require('../util/cast');
const xmlEscape = require('../util/xml-escape');

class Comment {
    /**
     * @param {string} id Id of the comment.
     * @param {string} text Text content of the comment.
     * @param {number} x X position of the comment on the workspace.
     * @param {number} y Y position of the comment on the workspace.
     * @param {number} width The width of the comment when it is full size.
     * @param {number} height The height of the comment when it is full size.
     * @param {boolean} minimized Whether the comment is minimized.
     * @constructor
     */
    constructor (id, text, x, y, width, height, minimized) {
        this.id = id || uid();
        this.text = text;
        this.x = x;
        this.y = y;
        this.width = Math.max(Cast.toNumber(width), Comment.MIN_WIDTH);
        this.height = Math.max(Cast.toNumber(height), Comment.MIN_HEIGHT);
        this.minimized = minimized || false;
        this.blockId = null;
    }

    toXML () {
        return `<comment id="${this.id}" x="${this.x}" y="${
            this.y}" w="${this.width}" h="${this.height}" pinned="${
            this.blockId !== null}" minimized="${this.minimized}">${xmlEscape(this.text)}</comment>`;
    }

    // TODO choose min and defaults for width and height
    static get MIN_WIDTH () {
        return 20;
    }

    static get MIN_HEIGHT () {
        return 20;
    }

    static get DEFAULT_WIDTH () {
        return 100;
    }

    static get DEFAULT_HEIGHT () {
        return 100;
    }

}

module.exports = Comment;
<|endoftext|>


<commit_before>// ==UserScript==
// @name        0chan webm
// @namespace   https://0chan.hk/webm
// @description Replace external WebM links with video tag.
// @downloadURL https://raw.githubusercontent.com/Kagami/video-tools/master/0chan-webm.user.js
// @updateURL   https://raw.githubusercontent.com/Kagami/video-tools/master/0chan-webm.user.js
// @include     https://0chan.hk/*
// @include     http://nullchan7msxi257.onion/*
// @version     0.1.2
// @grant       GM_xmlhttpRequest
// @grant       unsafeWindow
// @connect     my.mixtape.moe
// @connect     u.nya.is
// @connect     a.safe.moe
// @connect     a.pomf.cat
// @connect     gfycat.com
// @connect     0x0.st
// ==/UserScript==

var THUMB_SIZE = 200;
var ALLOWED_HOSTS = [
  "my.mixtape.moe", "u.nya.is",
  "a.safe.moe", "a.pomf.cat",
  "[a-z]+.gfycat.com",
  "0x0.st",
];
var ALLOWED_LINKS = ALLOWED_HOSTS.map(function(host) {
  host = host.replace(/\./g, "\\.");
  return new RegExp("^https?://" + host + "/.+\\.(webm|mp4)$");
});

function makeThumbnail(screenshot) {
  return new Promise(function(resolve, reject) {
    var img = document.createElement("img");
    img.addEventListener("load", function () {
      var c = document.createElement("canvas");
      var ctx = c.getContext("2d");
      var arrow = "\u25B6";
      var circle = "\u26AB";
      var textWidth = 0;
      var textHeight = THUMB_SIZE / 4;
      if (img.width > img.height) {
        c.width = THUMB_SIZE;
        c.height = (img.height*THUMB_SIZE) / img.width;
      } else {
        c.width = (img.width*THUMB_SIZE) / img.height;
        c.height = THUMB_SIZE;
      }
      ctx.drawImage(img, 0, 0, c.width, c.height);
      ctx.font = textHeight + "px sans-serif";
      ctx.fillStyle = "rgba(255, 255, 255, 0.8)";
      textWidth = ctx.measureText(circle).width;
      ctx.fillText(circle, c.width/2 - textWidth*0.55, c.height/2 + textHeight*0.45);
      textHeight /= 2;
      ctx.font = textHeight + "px sans-serif";
      ctx.fillStyle = "rgba(0, 0, 0, 0.8)";
      textWidth = ctx.measureText(arrow).width;
      ctx.fillText(arrow, c.width/2 - textWidth/2, c.height/2 + textHeight/2);
      resolve(c.toDataURL("image/png", 1.0));
    });
    img.addEventListener("error", reject);
    img.src = screenshot;
  });
}

function loadVideoDataFromURL(url) {
  return new Promise(function(resolve, reject) {
    GM_xmlhttpRequest({
      method: "GET",
      responseType: "blob",
      url: url,
      headers: {
        Range: "bytes=0-200000"  // Should be enough to get first frame
      },
      onload: function(response) {
        resolve(response.response);
      },
      onerror: function(e) {
        reject(e);
      },
    });
  });
}

function loadVideo(videoData) {
  return new Promise(function(resolve, reject) {
    var vid = document.createElement("video");
    vid.muted = true;
    vid.autoplay = false;
    vid.addEventListener("error", reject);
    vid.addEventListener("loadedmetadata", function() {
      resolve(vid);
    });
    vid.src = URL.createObjectURL(videoData);
  });
}

function getVideoScreenshot(vid) {
  var timePos = 0.0;
  return new Promise(function(resolve, reject) {
    var makeScreenshot = function() {
      var c = document.createElement("canvas");
      var ctx = c.getContext("2d");
      try {
        c.width = vid.videoWidth;
        c.height = vid.videoHeight;
        ctx.drawImage(vid, 0, 0, c.width, c.height);
      } catch (e) {
        reject(e);
        return;
      }
      resolve(c.toDataURL("image/png", 1.0));
    };
    if (vid.currentTime === timePos) {
      var HAVE_CURRENT_DATA = 2;
      var HAVE_METADATA = 1;
      if (vid.readyState >= HAVE_CURRENT_DATA) {
        makeScreenshot();
      } else if (vid.readyState === HAVE_METADATA) {
        vid.addEventListener("error", reject);
        vid.addEventListener("seeked", makeScreenshot);
        vid.currentTime = timePos;
      } else {
        reject(new Error());
      }
    } else {
      vid.addEventListener("error", reject);
      vid.addEventListener("seeked", makeScreenshot);
      vid.currentTime = timePos;
    }
  });
}

function embedVideo(link) {
  loadVideoDataFromURL(link.href)
  .then(loadVideo)
  .then(getVideoScreenshot)
  .then(makeThumbnail)
  .then(function(thumbnail) {
    var vid = document.createElement("video");

    vid.style.display = "block";
    vid.style.maxWidth = "200px";
    vid.style.maxHeight = "350px";

    vid.poster = thumbnail;
    vid.preload = "none";
    vid.loop = true;
    vid.controls = false;
    vid.src = link.href;
    vid.addEventListener("click", function(event) {
      if (!vid.controls) vid.play();
      vid.controls = true;
      vid.style.maxWidth = "none";
    });

    link.parentNode.replaceChild(vid, link);
  });
}

function handlePost(post) {
  var links = post.querySelectorAll("a[target=_blank]");
  Array.prototype.filter.call(links, function(link) {
    return ALLOWED_LINKS.some(function(re) {
      return re.test(link.href);
    });
  }).forEach(embedVideo);
}

// TODO: Handle OP post.
function handleThread(container) {
  var observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
      Array.prototype.filter.call(mutation.addedNodes, function(node) {
        return node.tagName === "DIV";
      }).forEach(handlePost);
    });
  });
  observer.observe(container, {childList: true});
  Array.prototype.forEach.call(container.children, handlePost);
}

unsafeWindow.webmHandler = exportFunction(function() {
  // TODO: Handle multiple threads.
  handleThread(document.querySelector(".thread-tree"));
}, unsafeWindow);

function handleApp(container) {
  // XXX: $bus is not yet available on DOMContentLoaded so wait for the
  // first mutation.
  var observer = new MutationObserver(function(mutations) {
    var app = unsafeWindow.app;
    app.$bus.on("refreshContentDone", unsafeWindow.webmHandler);
    observer.disconnect();
  });
  observer.observe(container, {childList: true});
}

handleApp(document.body);
<commit_msg>[0chan-webm] 0.1.3<commit_after>// ==UserScript==
// @name        0chan webm
// @namespace   https://0chan.hk/webm
// @description Replace external WebM links with video tag.
// @downloadURL https://raw.githubusercontent.com/Kagami/video-tools/master/0chan-webm.user.js
// @updateURL   https://raw.githubusercontent.com/Kagami/video-tools/master/0chan-webm.user.js
// @include     https://0chan.hk/*
// @include     http://nullchan7msxi257.onion/*
// @version     0.1.3
// @grant       GM_xmlhttpRequest
// @grant       unsafeWindow
// @connect     mixtape.moe
// @connect     u.nya.is
// @connect     a.safe.moe
// @connect     a.pomf.cat
// @connect     gfycat.com
// @connect     0x0.st
// ==/UserScript==

var THUMB_SIZE = 200;
var ALLOWED_HOSTS = [
  "[a-z0-9]+.mixtape.moe", "u.nya.is",
  "a.safe.moe", "a.pomf.cat",
  "[a-z]+.gfycat.com",
  "0x0.st",
];
var ALLOWED_LINKS = ALLOWED_HOSTS.map(function(host) {
  host = host.replace(/\./g, "\\.");
  return new RegExp("^https?://" + host + "/.+\\.(webm|mp4)$");
});

function makeThumbnail(screenshot) {
  return new Promise(function(resolve, reject) {
    var img = document.createElement("img");
    img.addEventListener("load", function () {
      var c = document.createElement("canvas");
      var ctx = c.getContext("2d");
      var arrow = "\u25B6";
      var circle = "\u26AB";
      var textWidth = 0;
      var textHeight = THUMB_SIZE / 4;
      if (img.width > img.height) {
        c.width = THUMB_SIZE;
        c.height = (img.height*THUMB_SIZE) / img.width;
      } else {
        c.width = (img.width*THUMB_SIZE) / img.height;
        c.height = THUMB_SIZE;
      }
      ctx.drawImage(img, 0, 0, c.width, c.height);
      ctx.font = textHeight + "px sans-serif";
      ctx.fillStyle = "rgba(255, 255, 255, 0.8)";
      textWidth = ctx.measureText(circle).width;
      ctx.fillText(circle, c.width/2 - textWidth*0.55, c.height/2 + textHeight*0.45);
      textHeight /= 2;
      ctx.font = textHeight + "px sans-serif";
      ctx.fillStyle = "rgba(0, 0, 0, 0.8)";
      textWidth = ctx.measureText(arrow).width;
      ctx.fillText(arrow, c.width/2 - textWidth/2, c.height/2 + textHeight/2);
      resolve(c.toDataURL("image/png", 1.0));
    });
    img.addEventListener("error", reject);
    img.src = screenshot;
  });
}

function loadVideoDataFromURL(url) {
  return new Promise(function(resolve, reject) {
    GM_xmlhttpRequest({
      method: "GET",
      responseType: "blob",
      url: url,
      headers: {
        Range: "bytes=0-200000"  // Should be enough to get first frame
      },
      onload: function(response) {
        resolve(response.response);
      },
      onerror: function(e) {
        reject(e);
      },
    });
  });
}

function loadVideo(videoData) {
  return new Promise(function(resolve, reject) {
    var vid = document.createElement("video");
    vid.muted = true;
    vid.autoplay = false;
    vid.addEventListener("error", reject);
    vid.addEventListener("loadedmetadata", function() {
      resolve(vid);
    });
    vid.src = URL.createObjectURL(videoData);
  });
}

function getVideoScreenshot(vid) {
  var timePos = 0.0;
  return new Promise(function(resolve, reject) {
    var makeScreenshot = function() {
      var c = document.createElement("canvas");
      var ctx = c.getContext("2d");
      try {
        c.width = vid.videoWidth;
        c.height = vid.videoHeight;
        ctx.drawImage(vid, 0, 0, c.width, c.height);
      } catch (e) {
        reject(e);
        return;
      }
      resolve(c.toDataURL("image/png", 1.0));
    };
    if (vid.currentTime === timePos) {
      var HAVE_CURRENT_DATA = 2;
      var HAVE_METADATA = 1;
      if (vid.readyState >= HAVE_CURRENT_DATA) {
        makeScreenshot();
      } else if (vid.readyState === HAVE_METADATA) {
        vid.addEventListener("error", reject);
        vid.addEventListener("seeked", makeScreenshot);
        vid.currentTime = timePos;
      } else {
        reject(new Error());
      }
    } else {
      vid.addEventListener("error", reject);
      vid.addEventListener("seeked", makeScreenshot);
      vid.currentTime = timePos;
    }
  });
}

function embedVideo(link) {
  loadVideoDataFromURL(link.href)
  .then(loadVideo)
  .then(getVideoScreenshot)
  .then(makeThumbnail)
  .then(function(thumbnail) {
    var vid = document.createElement("video");

    vid.style.display = "block";
    vid.style.maxWidth = "200px";
    vid.style.maxHeight = "350px";

    vid.poster = thumbnail;
    vid.preload = "none";
    vid.loop = true;
    vid.controls = false;
    vid.src = link.href;
    vid.addEventListener("click", function(event) {
      if (!vid.controls) vid.play();
      vid.controls = true;
      vid.style.maxWidth = "none";
    });

    link.parentNode.replaceChild(vid, link);
  });
}

function handlePost(post) {
  var links = post.querySelectorAll("a[target=_blank]");
  Array.prototype.filter.call(links, function(link) {
    return ALLOWED_LINKS.some(function(re) {
      return re.test(link.href);
    });
  }).forEach(embedVideo);
}

// TODO: Handle OP post.
function handleThread(container) {
  var observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
      Array.prototype.filter.call(mutation.addedNodes, function(node) {
        return node.tagName === "DIV";
      }).forEach(handlePost);
    });
  });
  observer.observe(container, {childList: true});
  Array.prototype.forEach.call(container.children, handlePost);
}

unsafeWindow.webmHandler = exportFunction(function() {
  // TODO: Handle multiple threads.
  handleThread(document.querySelector(".thread-tree"));
}, unsafeWindow);

function handleApp(container) {
  // XXX: $bus is not yet available on DOMContentLoaded so wait for the
  // first mutation.
  var observer = new MutationObserver(function(mutations) {
    var app = unsafeWindow.app;
    app.$bus.on("refreshContentDone", unsafeWindow.webmHandler);
    observer.disconnect();
  });
  observer.observe(container, {childList: true});
}

handleApp(document.body);
<|endoftext|>


<commit_before>/**
* @author       Richard Davey <rich@photonstorm.com>
* @copyright    2016 Photon Storm Ltd.
* @license      {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/

/**
* This is a base State class which can be extended if you are creating your own game.
* It provides quick access to common functions such as the camera, cache, input, match, sound and more.
*
* #### Callbacks
*
* | start | preload     | loaded     | paused       | stop     |
* |-------|-------------|------------|--------------|----------|
* | init  |             |            |              |          |
* |       | preload     | create     | paused       |          |
* |       | loadUpdate* | update*    | pauseUpdate* |          |
* |       |             | postUpdate*|              |          |
* |       |             | preRender* |              |          |
* |       | loadRender* | render*    | render*      |          |
* |       |             |            | resumed      |          |
* |       |             |            |              | shutdown |
*
* Update and render calls (*) are repeated.
*
* If your State has a constructor, it will be invoked exactly once, during {@link {@link Phaser.StateManager#add}.
*
* @class Phaser.State
* @constructor
*/
Phaser.State = function ()
{

    /**
    * @property {Phaser.Game} game - This is a reference to the currently running Game.
    */
    this.game = null;

    /**
    * @property {string} key - The string based identifier given to the State when added into the State Manager.
    */
    this.key = '';

    /**
    * @property {Phaser.GameObjectFactory} add - A reference to the GameObjectFactory which can be used to add new objects to the World.
    */
    this.add = null;

    /**
    * @property {Phaser.GameObjectCreator} make - A reference to the GameObjectCreator which can be used to make new objects.
    */
    this.make = null;

    /**
    * @property {Phaser.Camera} camera - A handy reference to World.camera.
    */
    this.camera = null;

    /**
    * @property {Phaser.Cache} cache - A reference to the game cache which contains any loaded or generated assets, such as images, sound and more.
    */
    this.cache = null;

    /**
    * @property {Phaser.Input} input - A reference to the Input Manager.
    */
    this.input = null;

    /**
    * @property {Phaser.Loader} load - A reference to the Loader, which you mostly use in the preload method of your state to load external assets.
    */
    this.load = null;

    /**
    * @property {Phaser.Math} math - A reference to Math class with lots of helpful functions.
    */
    this.math = null;

    /**
    * @property {Phaser.SoundManager} sound - A reference to the Sound Manager which can create, play and stop sounds, as well as adjust global volume.
    */
    this.sound = null;

    /**
    * @property {Phaser.ScaleManager} scale - A reference to the Scale Manager which controls the way the game scales on different displays.
    */
    this.scale = null;

    /**
    * @property {Phaser.Stage} stage - A reference to the Stage.
    */
    this.stage = null;

    /**
    * @property {Phaser.StateManager} state - A reference to the State Manager, which controls state changes.
    */
    this.state = null;

    /**
    * @property {Phaser.Time} time - A reference to the game clock and timed events system.
    */
    this.time = null;

    /**
    * @property {Phaser.TweenManager} tweens - A reference to the tween manager.
    */
    this.tweens = null;

    /**
    * @property {Phaser.World} world - A reference to the game world. All objects live in the Game World and its size is not bound by the display resolution.
    */
    this.world = null;

    /**
    * @property {Phaser.Particles} particles - The Particle Manager. It is called during the core gameloop and updates any Particle Emitters it has created.
    */
    this.particles = null;

    /**
    * @property {Phaser.Physics} physics - A reference to the physics manager which looks after the different physics systems available within Phaser.
    */
    this.physics = null;

    /**
    * @property {Phaser.RandomDataGenerator} rnd - A reference to the seeded and repeatable random data generator.
    */
    this.rnd = null;

};

Phaser.State.prototype = {

    /**
    * init is the very first function called when your State starts up. It's called before preload, create or anything else.
    * If you need to route the game away to another State you could do so here, or if you need to prepare a set of variables
    * or objects before the preloading starts.
    *
    * @method Phaser.State#init
    * @param {...any} args - Any extra arguments passed to {@link Phaser.StateManager#start} or {@link Phaser.StateManager#restart}.
    */
    init: function ()
    {
    },

    /**
    * preload is called first. Normally you'd use this to load your game assets (or those needed for the current State)
    * You shouldn't create any objects in this method that require assets that you're also loading in this method, as
    * they won't yet be available.
    *
    * @method Phaser.State#preload
    * @param {Phaser.Game} game
    */
    preload: function ()
    {
    },

    /**
    * loadUpdate is called during the Loader process. This only happens if you've set one or more assets to load in the preload method.
    *
    * @method Phaser.State#loadUpdate
    * @param {Phaser.Game} game
    */
    loadUpdate: function ()
    {
    },

    /**
    * loadRender is called during the Loader process. This only happens if you've set one or more assets to load in the preload method.
    * The difference between loadRender and render is that any objects you render in this method you must be sure their assets exist.
    *
    * @method Phaser.State#loadRender
    * @param {Phaser.Game} game
    */
    loadRender: function ()
    {
    },

    /**
    * create is called once preload has completed, this includes the loading of any assets from the Loader.
    * If you don't have a preload method then create is the first method called in your State.
    *
    * @method Phaser.State#create
    * @param {Phaser.Game} game
    */
    create: function ()
    {
    },

    /**
    * The update method is left empty for your own use.
    * It is called during the core game loop AFTER debug, physics, plugins and the Stage have had their preUpdate methods called.
    * It is called BEFORE Stage, Tweens, Sounds, Input, Physics, Particles and Plugins have had their postUpdate methods called.
    *
    * @method Phaser.State#update
    * @param {Phaser.Game} game
    */
    update: function ()
    {
    },

    /**
    * The postUpdate method is left empty for your own use.
    * It is called during the core game loop AFTER the Stage has had its postUpdate method called (including updateTransform).
    * It is called BEFORE Plugins have had their postUpdate methods called.
    *
    * @method Phaser.State#postUpdate
    * @param {Phaser.Game} game
    */
    postUpdate: function ()
    {
    },

    /**
    * The preRender method is called after all Game Objects have been updated, but before any rendering takes place.
    *
    * @method Phaser.State#preRender
    * @param {Phaser.Game} game
    * @param {number} elapsedTime
    */
    preRender: function ()
    {
    },

    /**
    * Nearly all display objects in Phaser render automatically, you don't need to tell them to render.
    * However the render method is called AFTER the game renderer and plugins have rendered, so you're able to do any
    * final post-processing style effects here. Note that this happens before plugins postRender takes place.
    *
    * @method Phaser.State#render
    * @param {Phaser.Game} game
    */
    render: function ()
    {
    },

    /**
    * If your game is set to Scalemode RESIZE then each time the browser resizes it will call this function, passing in the new width and height.
    *
    * @method Phaser.State#resize
    * @param {number} width
    * @param {number} height
    */
    resize: function ()
    {
    },

    /**
    * This method will be called if the core game loop is paused.
    *
    * @method Phaser.State#paused
    * @param {Phaser.Game} game
    */
    paused: function ()
    {
    },

    /**
    * This method will be called when the core game loop resumes from a paused state.
    *
    * @method Phaser.State#resumed
    * @param {Phaser.Game} game
    */
    resumed: function ()
    {
    },

    /**
    * pauseUpdate is called while the game is paused instead of preUpdate, update and postUpdate.
    *
    * @method Phaser.State#pauseUpdate
    * @param {Phaser.Game} game
    */
    pauseUpdate: function ()
    {
    },

    /**
    * This method will be called when the State is shutdown (i.e. you switch to another state from this one).
    *
    * @method Phaser.State#shutdown
    * @param {Phaser.Game} game
    */
    shutdown: function ()
    {
    }

};

Phaser.State.prototype.constructor = Phaser.State;
<commit_msg>Docs for State#postUpdate<commit_after>/**
* @author       Richard Davey <rich@photonstorm.com>
* @copyright    2016 Photon Storm Ltd.
* @license      {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/

/**
* This is a base State class which can be extended if you are creating your own game.
* It provides quick access to common functions such as the camera, cache, input, match, sound and more.
*
* #### Callbacks
*
* | start | preload     | loaded     | paused       | stop     |
* |-------|-------------|------------|--------------|----------|
* | init  |             |            |              |          |
* |       | preload     | create     | paused       |          |
* |       | loadUpdate* | update*    | pauseUpdate* |          |
* |       |             | postUpdate*|              |          |
* |       |             | preRender* |              |          |
* |       | loadRender* | render*    | render*      |          |
* |       |             |            | resumed      |          |
* |       |             |            |              | shutdown |
*
* Update and render calls (*) are repeated.
*
* If your State has a constructor, it will be invoked exactly once, during {@link {@link Phaser.StateManager#add}.
*
* @class Phaser.State
* @constructor
*/
Phaser.State = function ()
{

    /**
    * @property {Phaser.Game} game - This is a reference to the currently running Game.
    */
    this.game = null;

    /**
    * @property {string} key - The string based identifier given to the State when added into the State Manager.
    */
    this.key = '';

    /**
    * @property {Phaser.GameObjectFactory} add - A reference to the GameObjectFactory which can be used to add new objects to the World.
    */
    this.add = null;

    /**
    * @property {Phaser.GameObjectCreator} make - A reference to the GameObjectCreator which can be used to make new objects.
    */
    this.make = null;

    /**
    * @property {Phaser.Camera} camera - A handy reference to World.camera.
    */
    this.camera = null;

    /**
    * @property {Phaser.Cache} cache - A reference to the game cache which contains any loaded or generated assets, such as images, sound and more.
    */
    this.cache = null;

    /**
    * @property {Phaser.Input} input - A reference to the Input Manager.
    */
    this.input = null;

    /**
    * @property {Phaser.Loader} load - A reference to the Loader, which you mostly use in the preload method of your state to load external assets.
    */
    this.load = null;

    /**
    * @property {Phaser.Math} math - A reference to Math class with lots of helpful functions.
    */
    this.math = null;

    /**
    * @property {Phaser.SoundManager} sound - A reference to the Sound Manager which can create, play and stop sounds, as well as adjust global volume.
    */
    this.sound = null;

    /**
    * @property {Phaser.ScaleManager} scale - A reference to the Scale Manager which controls the way the game scales on different displays.
    */
    this.scale = null;

    /**
    * @property {Phaser.Stage} stage - A reference to the Stage.
    */
    this.stage = null;

    /**
    * @property {Phaser.StateManager} state - A reference to the State Manager, which controls state changes.
    */
    this.state = null;

    /**
    * @property {Phaser.Time} time - A reference to the game clock and timed events system.
    */
    this.time = null;

    /**
    * @property {Phaser.TweenManager} tweens - A reference to the tween manager.
    */
    this.tweens = null;

    /**
    * @property {Phaser.World} world - A reference to the game world. All objects live in the Game World and its size is not bound by the display resolution.
    */
    this.world = null;

    /**
    * @property {Phaser.Particles} particles - The Particle Manager. It is called during the core gameloop and updates any Particle Emitters it has created.
    */
    this.particles = null;

    /**
    * @property {Phaser.Physics} physics - A reference to the physics manager which looks after the different physics systems available within Phaser.
    */
    this.physics = null;

    /**
    * @property {Phaser.RandomDataGenerator} rnd - A reference to the seeded and repeatable random data generator.
    */
    this.rnd = null;

};

Phaser.State.prototype = {

    /**
    * init is the very first function called when your State starts up. It's called before preload, create or anything else.
    * If you need to route the game away to another State you could do so here, or if you need to prepare a set of variables
    * or objects before the preloading starts.
    *
    * @method Phaser.State#init
    * @param {...any} args - Any extra arguments passed to {@link Phaser.StateManager#start} or {@link Phaser.StateManager#restart}.
    */
    init: function ()
    {
    },

    /**
    * preload is called first. Normally you'd use this to load your game assets (or those needed for the current State)
    * You shouldn't create any objects in this method that require assets that you're also loading in this method, as
    * they won't yet be available.
    *
    * @method Phaser.State#preload
    * @param {Phaser.Game} game
    */
    preload: function ()
    {
    },

    /**
    * loadUpdate is called during the Loader process. This only happens if you've set one or more assets to load in the preload method.
    *
    * @method Phaser.State#loadUpdate
    * @param {Phaser.Game} game
    */
    loadUpdate: function ()
    {
    },

    /**
    * loadRender is called during the Loader process. This only happens if you've set one or more assets to load in the preload method.
    * The difference between loadRender and render is that any objects you render in this method you must be sure their assets exist.
    *
    * @method Phaser.State#loadRender
    * @param {Phaser.Game} game
    */
    loadRender: function ()
    {
    },

    /**
    * create is called once preload has completed, this includes the loading of any assets from the Loader.
    * If you don't have a preload method then create is the first method called in your State.
    *
    * @method Phaser.State#create
    * @param {Phaser.Game} game
    */
    create: function ()
    {
    },

    /**
    * The update method is left empty for your own use.
    * It is called during the core game loop AFTER debug, physics, plugins and the Stage have had their preUpdate methods called.
    * It is called BEFORE Stage, Tweens, Sounds, Input, Physics, Particles and Plugins have had their postUpdate methods called.
    *
    * @method Phaser.State#update
    * @param {Phaser.Game} game
    */
    update: function ()
    {
    },

    /**
    * The postUpdate method is left empty for your own use.
    * It is called during the core game loop AFTER the Stage has had its postUpdate method called (including updateTransform).
    * It is called BEFORE Plugins have had their postUpdate methods called.
    * You don't need to call updateTransform yourself here unless Plugins need it.
    *
    * @method Phaser.State#postUpdate
    * @param {Phaser.Game} game
    */
    postUpdate: function ()
    {
    },

    /**
    * The preRender method is called after all Game Objects have been updated, but before any rendering takes place.
    *
    * @method Phaser.State#preRender
    * @param {Phaser.Game} game
    * @param {number} elapsedTime
    */
    preRender: function ()
    {
    },

    /**
    * Nearly all display objects in Phaser render automatically, you don't need to tell them to render.
    * However the render method is called AFTER the game renderer and plugins have rendered, so you're able to do any
    * final post-processing style effects here. Note that this happens before plugins postRender takes place.
    *
    * @method Phaser.State#render
    * @param {Phaser.Game} game
    */
    render: function ()
    {
    },

    /**
    * If your game is set to Scalemode RESIZE then each time the browser resizes it will call this function, passing in the new width and height.
    *
    * @method Phaser.State#resize
    * @param {number} width
    * @param {number} height
    */
    resize: function ()
    {
    },

    /**
    * This method will be called if the core game loop is paused.
    *
    * @method Phaser.State#paused
    * @param {Phaser.Game} game
    */
    paused: function ()
    {
    },

    /**
    * This method will be called when the core game loop resumes from a paused state.
    *
    * @method Phaser.State#resumed
    * @param {Phaser.Game} game
    */
    resumed: function ()
    {
    },

    /**
    * pauseUpdate is called while the game is paused instead of preUpdate, update and postUpdate.
    *
    * @method Phaser.State#pauseUpdate
    * @param {Phaser.Game} game
    */
    pauseUpdate: function ()
    {
    },

    /**
    * This method will be called when the State is shutdown (i.e. you switch to another state from this one).
    *
    * @method Phaser.State#shutdown
    * @param {Phaser.Game} game
    */
    shutdown: function ()
    {
    }

};

Phaser.State.prototype.constructor = Phaser.State;
<|endoftext|>


<commit_before>/* **********************************************************************
    Copyright 2008 Rensselaer Polytechnic Institute. All worldwide rights reserved.

    Redistribution and use of this distribution in source and binary forms,
    with or without modification, are permitted provided that:
       The above copyright notice and this permission notice appear in all
        copies and supporting documentation;

        The name, identifiers, and trademarks of Rensselaer Polytechnic
        Institute are not used in advertising or publicity without the
        express prior written permission of Rensselaer Polytechnic Institute;

    DISCLAIMER: The software is distributed" AS IS" without any express or
    implied warranty, including but not limited to, any implied warranties
    of merchantability or fitness for a particular purpose or any warrant)'
    of non-infringement of any current or pending patent rights. The authors
    of the software make no representations about the suitability of this
    software for any particular purpose. The entire risk as to the quality
    and performance of the software is with the user. Should the software
    prove defective, the user assumes the cost of all necessary servicing,
    repair or correction. In particular, neither Rensselaer Polytechnic
    Institute, nor the authors of the software are liable for any indirect,
    special, consequential, or incidental damages related to the software,
    to the maximum extent the law permits. */

/* NOTE: this file is different between Bedework web applications and is
   therefore not currently interchangable between apps.  This will be normalized
   in the coming versions, but for now don't try to exchange them. */

var debug = false; // very basic debugging for now

/* COMMON and GENERAL FUNCTIONS */

function changeClass(id, newClass) {
  var identity = document.getElementById(id);
  if (identity == null) {
    alert("No element with id: " + id + " to set to class: " + newClass);
  }
  identity.className=newClass;
}
// set a field's value by ID
// typically used to set the value of a hidden field
function setField(id,val) {
  field = document.getElementById(id);
  field.value = val;
}

// show hide items using a checkbox
function swapVisible(obj,id) {
  if (obj.checked) {
    changeClass(id,'visible');
  } else {
    changeClass(id,'invisible');
  }
}
// hide a group of items
// send IDs as parameters
function hide() {
  if (arguments.length != 0) {
    for (i = 0; i < arguments.length; i++) {
      changeClass(arguments[i],'invisible');
    }
  }
}
// show a group of items
// send IDs as parameters
function show() {
  if (arguments.length != 0) {
    for (i = 0; i < arguments.length; i++) {
      changeClass(arguments[i],'visible');
    }
  }
}
// show and hide an item based on its current
// visibility; if visible, hide it; if invisible
// show it.
function toggleVisibility(id,newClass) {
  if (document.getElementById(id).className == 'invisible') {
    if (newClass != "") {
      changeClass(id,newClass);
    } else {
      changeClass(id,'visible');
    }
  } else {
    changeClass(id,'invisible');
  }
}
function setTab(listId,listIndex) {
  var list = document.getElementById(listId);
  var elementArray = new Array();
  for (i = 0; i < list.childNodes.length; i++) {
    if (list.childNodes[i].nodeName == "LI") {
      elementArray.push(list.childNodes[i]);
    }
  }
  for (i = 0; i < elementArray.length; i++) {
    if (i == listIndex) {
      elementArray[i].className = 'selected';
    } else {
      elementArray[i].className = '';
    }
  }
}
function getSelectedRadioButtonVal(radioCollection) {
  for(var i = 0; i < radioCollection.length; i++) {
    if(radioCollection[i].checked == true) {
       return radioCollection[i].value;
    }
  }
}
// returns an array of collected checkbox values
function collectRecurChkBoxVals(valArray,chkBoxes,dayPos) {
  if (chkBoxes) {
    if (typeof chkBoxes.length != 'undefined') {
      for (i = 0; i < chkBoxes.length; i++) {
        if (chkBoxes[i].checked == true) {
          if (dayPos) {
            valArray.push(dayPos + chkBoxes[i].value);
          } else {
            valArray.push(chkBoxes[i].value);
          }
        }
      }
    }
  }
  return valArray;
}
// launch a simple window for displaying information; no header or status bar
function launchSimpleWindow(URL) {
  simpleWindow = window.open(URL, "simpleWindow", "width=800,height=600,scrollbars=yes,resizable=yes,alwaysRaised=yes,menubar=no,toolbar=no");
  window.simpleWindow.focus();
}

// launch a size parameterized window for displaying information; no header or status bar
function launchSizedWindow(URL,width,height) {
  paramStr = "width=" + width + ",height=" + height + ",scrollbars=yes,resizable=yes,alwaysRaised=yes,menubar=no,toolbar=no";
  sizedWindow = window.open(URL, "sizedWindow", paramStr);
  window.sizedWindow.focus();
}

// launches new browser window with print-friendly version of page when
// print icon is clicked
function launchPrintWindow(URL) {
  printWindow = window.open(URL, "printWindow", "width=640,height=500,scrollbars=yes,resizable=yes,alwaysRaised=yes,menubar=yes,toolbar=yes");
  window.printWindow.focus();
}
// launch the calSelect pop-up window for selecting a calendar when creating,
// editing, and importing events
function launchCalSelectWindow(URL) {
  calSelect = window.open(URL, "calSelect", "width=500,height=600,scrollbars=yes,resizable=yes,alwaysRaised=yes,menubar=no,toolbar=no");
  window.calSelect.focus();
}
// used to update the calendar in various forms from
// the calSelect pop-up window.  We must do two things: update the hidden calendar
// input field and update the displayed text.
function updateEventFormCalendar(newCalPath,calDisplay) {
  if (window.opener.document.eventForm) {
    window.opener.document.eventForm.newCalPath.value = newCalPath;
    bwCalDisplay = window.opener.document.getElementById("bwEventCalDisplay");
    bwCalDisplay.innerHTML = calDisplay;
  } else {
    alert("The event form is not available.");
  }
  window.close();
}
// used to update a calendar subscription (alias) We must do two things: update the hidden
// calendar input field and update the displayed text
function updatePublicCalendarAlias(newCalPath,calDisplay,calendarCollection) {
  var calendarAliasHolder = document.getElementById("publicAliasHolder");
  var bwCalDisplay = document.getElementById("bwPublicCalDisplay");
  calendarAliasHolder.value = newCalPath;
  bwCalDisplay.innerHTML = '' + calDisplay + ' <button type="button" onclick="showPublicCalAliasTree();">change</button>';
  changeClass("publicSubscriptionTree","invisible");
}
function showPublicCalAliasTree() {
  changeClass("publicSubscriptionTree","calendarTree");
}
// set the subscription URI when creating or updating a subscription
function setCalendarAlias(formObj) {
  if (!formObj) {
    alert("The subscription form is not available.");
    return false;
  }

  // set the aliasUri to an empty string.  Only set it if user
  // has requested a subscription.
  formObj.aliasUri.value == "";

  if (formObj.type.value == "folder") {
    formObj.calendarCollection.value = "false";
  } else if (formObj.type.value == "subscription") {
    switch (formObj.subType.value) {
      case "public":
        formObj.aliasUri.value = "bwcal://" + formObj.publicAliasHolder.value;
        break;
      case "user":
        //the "/user/" string is temporary; it needs to be passed as a param.
        formObj.aliasUri.value = "bwcal:///user/" + formObj.userIdHolder.value + "/" + formObj.userCalHolder.value;
        break;
      case "external":
        formObj.aliasUri.value = formObj.aliasUriHolder.value;
        break;
    }
  }
  return true;
}
// build a uri based on user and path in the subscription form
// DEPRECATED - use setCalendarAlias() above.
function setSubscriptionUri(formObj,prefix) {
  if (formObj) {
    var fullUri =  prefix + formObj.userId.value;
    if (formObj.userPath.value != "") {
      if (formObj.userPath.value.substring(0,1) == "/") {
        fullUri += formObj.userPath.value;
      } else {
        fullUri += "/" + formObj.userPath.value;
      }
    }
    formObj.calUri.value = fullUri;
    return true;
  } else {
    alert("The subscription form is not available.");
    return false;
  }
}
function exportCalendar(formId,name,calPath) {
  var formObj = document.getElementById(formId);
  formObj.calPath.value = calPath;
  formObj.contentName.value = name + '.ics';
  formObj.submit();
}

// checkboxes for all categories and preferred categories are on the page
// simultaneously.  The use can toggle between which is shown and which is
// hidden.  When a checkbox from one collection is changed, the corresponding
// checkbox should be changed in the other set if it exists.
function setCatChBx(thiscat,othercat) {
  thisCatCheckBox = document.getElementById(thiscat);
  if (document.getElementById(othercat)) {
    otherCatCheckBox = document.getElementById(othercat);
    otherCatCheckBox.checked =  thisCatCheckBox.checked;
  }
}
function checkPrefCategories(formObj){
  var hasACat = false;

  if (typeof formObj.defaultCategory.length != 'undefined') {
    for (i = 0; i < formObj.defaultCategory.length; i++) {
      if (formObj.defaultCategory[i].checked) {
        hasACat = true;
        break;
      }
    }
  }
  if (!hasACat) {
    // no category is checked;
    // create an empty catUid element to alert the backend
    // so we can clear the cats
    var hiddenCat = document.createElement("div");
    hiddenCat.innerHTML = '<input type="hidden" name="defaultCategory" value=""/>';
    formObj.appendChild(hiddenCat);
  }
}
// set category filters on calendar collections
function setCatFilters(formObj) {
  if (typeof formObj.filterCatUid.length != 'undefined') {
    var filterExpression = "catuid=(";
    var filterExists = false;
    for (i = 0; i < formObj.filterCatUid.length; i++) {
      if (formObj.filterCatUid[i].checked) {
        filterExists = true;
        filterExpression += formObj.filterCatUid[i].value + ",";
        alert(filterExpression);
        alert(filterExists);
      }
    }
    alert(filterExists);
    if (filterExists) {
      // remove the last comma and close off the expression
      filterExpression = filterExpression.substring(0,filterExpression.length-1) + ")";
      alert(filterExpression);
      // set the form value
      formObj.fexpr.value = filterExpression;
    }
  }
}
<commit_msg>admin client: set category filter expressions on calendar collections<commit_after>/* **********************************************************************
    Copyright 2008 Rensselaer Polytechnic Institute. All worldwide rights reserved.

    Redistribution and use of this distribution in source and binary forms,
    with or without modification, are permitted provided that:
       The above copyright notice and this permission notice appear in all
        copies and supporting documentation;

        The name, identifiers, and trademarks of Rensselaer Polytechnic
        Institute are not used in advertising or publicity without the
        express prior written permission of Rensselaer Polytechnic Institute;

    DISCLAIMER: The software is distributed" AS IS" without any express or
    implied warranty, including but not limited to, any implied warranties
    of merchantability or fitness for a particular purpose or any warrant)'
    of non-infringement of any current or pending patent rights. The authors
    of the software make no representations about the suitability of this
    software for any particular purpose. The entire risk as to the quality
    and performance of the software is with the user. Should the software
    prove defective, the user assumes the cost of all necessary servicing,
    repair or correction. In particular, neither Rensselaer Polytechnic
    Institute, nor the authors of the software are liable for any indirect,
    special, consequential, or incidental damages related to the software,
    to the maximum extent the law permits. */

/* NOTE: this file is different between Bedework web applications and is
   therefore not currently interchangable between apps.  This will be normalized
   in the coming versions, but for now don't try to exchange them. */

var debug = false; // very basic debugging for now

/* COMMON and GENERAL FUNCTIONS */

function changeClass(id, newClass) {
  var identity = document.getElementById(id);
  if (identity == null) {
    alert("No element with id: " + id + " to set to class: " + newClass);
  }
  identity.className=newClass;
}
// set a field's value by ID
// typically used to set the value of a hidden field
function setField(id,val) {
  field = document.getElementById(id);
  field.value = val;
}

// show hide items using a checkbox
function swapVisible(obj,id) {
  if (obj.checked) {
    changeClass(id,'visible');
  } else {
    changeClass(id,'invisible');
  }
}
// hide a group of items
// send IDs as parameters
function hide() {
  if (arguments.length != 0) {
    for (i = 0; i < arguments.length; i++) {
      changeClass(arguments[i],'invisible');
    }
  }
}
// show a group of items
// send IDs as parameters
function show() {
  if (arguments.length != 0) {
    for (i = 0; i < arguments.length; i++) {
      changeClass(arguments[i],'visible');
    }
  }
}
// show and hide an item based on its current
// visibility; if visible, hide it; if invisible
// show it.
function toggleVisibility(id,newClass) {
  if (document.getElementById(id).className == 'invisible') {
    if (newClass != "") {
      changeClass(id,newClass);
    } else {
      changeClass(id,'visible');
    }
  } else {
    changeClass(id,'invisible');
  }
}
function setTab(listId,listIndex) {
  var list = document.getElementById(listId);
  var elementArray = new Array();
  for (i = 0; i < list.childNodes.length; i++) {
    if (list.childNodes[i].nodeName == "LI") {
      elementArray.push(list.childNodes[i]);
    }
  }
  for (i = 0; i < elementArray.length; i++) {
    if (i == listIndex) {
      elementArray[i].className = 'selected';
    } else {
      elementArray[i].className = '';
    }
  }
}
function getSelectedRadioButtonVal(radioCollection) {
  for(var i = 0; i < radioCollection.length; i++) {
    if(radioCollection[i].checked == true) {
       return radioCollection[i].value;
    }
  }
}
// returns an array of collected checkbox values
function collectRecurChkBoxVals(valArray,chkBoxes,dayPos) {
  if (chkBoxes) {
    if (typeof chkBoxes.length != 'undefined') {
      for (i = 0; i < chkBoxes.length; i++) {
        if (chkBoxes[i].checked == true) {
          if (dayPos) {
            valArray.push(dayPos + chkBoxes[i].value);
          } else {
            valArray.push(chkBoxes[i].value);
          }
        }
      }
    }
  }
  return valArray;
}
// launch a simple window for displaying information; no header or status bar
function launchSimpleWindow(URL) {
  simpleWindow = window.open(URL, "simpleWindow", "width=800,height=600,scrollbars=yes,resizable=yes,alwaysRaised=yes,menubar=no,toolbar=no");
  window.simpleWindow.focus();
}

// launch a size parameterized window for displaying information; no header or status bar
function launchSizedWindow(URL,width,height) {
  paramStr = "width=" + width + ",height=" + height + ",scrollbars=yes,resizable=yes,alwaysRaised=yes,menubar=no,toolbar=no";
  sizedWindow = window.open(URL, "sizedWindow", paramStr);
  window.sizedWindow.focus();
}

// launches new browser window with print-friendly version of page when
// print icon is clicked
function launchPrintWindow(URL) {
  printWindow = window.open(URL, "printWindow", "width=640,height=500,scrollbars=yes,resizable=yes,alwaysRaised=yes,menubar=yes,toolbar=yes");
  window.printWindow.focus();
}
// launch the calSelect pop-up window for selecting a calendar when creating,
// editing, and importing events
function launchCalSelectWindow(URL) {
  calSelect = window.open(URL, "calSelect", "width=500,height=600,scrollbars=yes,resizable=yes,alwaysRaised=yes,menubar=no,toolbar=no");
  window.calSelect.focus();
}
// used to update the calendar in various forms from
// the calSelect pop-up window.  We must do two things: update the hidden calendar
// input field and update the displayed text.
function updateEventFormCalendar(newCalPath,calDisplay) {
  if (window.opener.document.eventForm) {
    window.opener.document.eventForm.newCalPath.value = newCalPath;
    bwCalDisplay = window.opener.document.getElementById("bwEventCalDisplay");
    bwCalDisplay.innerHTML = calDisplay;
  } else {
    alert("The event form is not available.");
  }
  window.close();
}
// used to update a calendar subscription (alias) We must do two things: update the hidden
// calendar input field and update the displayed text
function updatePublicCalendarAlias(newCalPath,calDisplay,calendarCollection) {
  var calendarAliasHolder = document.getElementById("publicAliasHolder");
  var bwCalDisplay = document.getElementById("bwPublicCalDisplay");
  calendarAliasHolder.value = newCalPath;
  bwCalDisplay.innerHTML = '' + calDisplay + ' <button type="button" onclick="showPublicCalAliasTree();">change</button>';
  changeClass("publicSubscriptionTree","invisible");
}
function showPublicCalAliasTree() {
  changeClass("publicSubscriptionTree","calendarTree");
}
// set the subscription URI when creating or updating a subscription
function setCalendarAlias(formObj) {
  if (!formObj) {
    alert("The subscription form is not available.");
    return false;
  }

  // set the aliasUri to an empty string.  Only set it if user
  // has requested a subscription.
  formObj.aliasUri.value == "";

  if (formObj.type.value == "folder") {
    formObj.calendarCollection.value = "false";
  } else if (formObj.type.value == "subscription") {
    switch (formObj.subType.value) {
      case "public":
        formObj.aliasUri.value = "bwcal://" + formObj.publicAliasHolder.value;
        break;
      case "user":
        //the "/user/" string is temporary; it needs to be passed as a param.
        formObj.aliasUri.value = "bwcal:///user/" + formObj.userIdHolder.value + "/" + formObj.userCalHolder.value;
        break;
      case "external":
        formObj.aliasUri.value = formObj.aliasUriHolder.value;
        break;
    }
  }
  return true;
}
// build a uri based on user and path in the subscription form
// DEPRECATED - use setCalendarAlias() above.
function setSubscriptionUri(formObj,prefix) {
  if (formObj) {
    var fullUri =  prefix + formObj.userId.value;
    if (formObj.userPath.value != "") {
      if (formObj.userPath.value.substring(0,1) == "/") {
        fullUri += formObj.userPath.value;
      } else {
        fullUri += "/" + formObj.userPath.value;
      }
    }
    formObj.calUri.value = fullUri;
    return true;
  } else {
    alert("The subscription form is not available.");
    return false;
  }
}
function exportCalendar(formId,name,calPath) {
  var formObj = document.getElementById(formId);
  formObj.calPath.value = calPath;
  formObj.contentName.value = name + '.ics';
  formObj.submit();
}

// checkboxes for all categories and preferred categories are on the page
// simultaneously.  The use can toggle between which is shown and which is
// hidden.  When a checkbox from one collection is changed, the corresponding
// checkbox should be changed in the other set if it exists.
function setCatChBx(thiscat,othercat) {
  thisCatCheckBox = document.getElementById(thiscat);
  if (document.getElementById(othercat)) {
    otherCatCheckBox = document.getElementById(othercat);
    otherCatCheckBox.checked =  thisCatCheckBox.checked;
  }
}
function checkPrefCategories(formObj){
  var hasACat = false;

  if (typeof formObj.defaultCategory.length != 'undefined') {
    for (i = 0; i < formObj.defaultCategory.length; i++) {
      if (formObj.defaultCategory[i].checked) {
        hasACat = true;
        break;
      }
    }
  }
  if (!hasACat) {
    // no category is checked;
    // create an empty catUid element to alert the backend
    // so we can clear the cats
    var hiddenCat = document.createElement("div");
    hiddenCat.innerHTML = '<input type="hidden" name="defaultCategory" value=""/>';
    formObj.appendChild(hiddenCat);
  }
}
// set category filters on calendar collections
function setCatFilters(formObj) {
  if (typeof formObj.filterCatUid.length != 'undefined') {
    var filterExpression = "catuid=(";
    var filterExists = false;
    for (i = 0; i < formObj.filterCatUid.length; i++) {
      if (formObj.filterCatUid[i].checked) {
        filterExists = true;
        filterExpression += formObj.filterCatUid[i].value + ",";
      }
    }
    alert(filterExists);
    if (filterExists) {
      // remove the last comma and close off the expression
      filterExpression = filterExpression.substring(0,filterExpression.length-1) + ")";
      // set the form value
      formObj.fexpr.value = filterExpression;
    }
  }
}
<|endoftext|>


<commit_before>/**
 * sessionAuth
 *
 * @module      :: Policy
 * @description :: Simple policy to allow any authenticated user
 *                 Assumes that your login action in one of your controllers sets `req.session.authenticated = true;`
 * @docs        :: http://sailsjs.org/#!documentation/policies
 *
 */
module.exports = function(req, res, next) {

  sails.log.debug("user: " + req.user);

  // User is allowed, proceed to the next policy,
  // or if this is the last policy, the controller
  if (req.session.authenticated) {
    next();
  } else {
    // User is not allowed
    // (default res.forbidden() behavior can be overridden in `config/403.js`)
    res.forbidden();
  }
};
<commit_msg>remove debug statement<commit_after>/**
 * sessionAuth
 *
 * @module      :: Policy
 * @description :: Simple policy to allow any authenticated user
 *                 Assumes that your login action in one of your controllers sets `req.session.authenticated = true;`
 * @docs        :: http://sailsjs.org/#!documentation/policies
 *
 */
module.exports = function(req, res, next) {

  // User is allowed, proceed to the next policy,
  // or if this is the last policy, the controller
  if (req.session.authenticated) {
    next();
  } else {
    // User is not allowed
    // (default res.forbidden() behavior can be overridden in `config/403.js`)
    res.forbidden();
  }
};
<|endoftext|>


<commit_before>/**
* @author       Alan Smithee <ggnore.alan.smithee@gmail.com>
* @copyright    2015 GGNoRe.
* @license      {@link https://github.com/GGAlanSmithee/Entities/blob/master/LICENSE|MIT License}
*/

'use strict';

Entities.World = function(size, type) {
    this.ComponentType = {
        None : 0
    };

    this.Size = size ? size : 100;

    this.Type = type !== undefined ? type : Entities.World.Type.Static;

    this.Mask = [];

    for (var i = 0; i < this.Size; ++i) {
        this.Mask.push(this.ComponentType.None);
    }
};

Entities.World.Type = {
    Dynamic : 0,
    SemiDynamic : 1,
    Static : 2
};

Entities.World.prototype = {
    constructor : Entities.World,

    MinRatio : 0.0,

    MaxRatio : 4.0,

    registerComponent : function(component, ratio) {
        var arr = [];

        for (var type in this.ComponentType) {
           if (this.ComponentType.hasOwnProperty(type)) {
                arr.push(this.ComponentType[type]);
            }
        }

        var max = Math.max.apply(null, arr);

        this.ComponentType[component.name] = max === undefined || max === null ? 0: max === 0 ? 1 : max * 2;

        if (this[component.name]) {
            return;
        }

        this[component.name] = [];

        if (this.Type === Entities.World.Type.Dynamic || this.Type === Entities.World.Type.SemiDynamic) {
            return;
        }

        for (var i = 0; i < this.Size; ++i) {
            this[component.name].push(new global[component.name]());
        }
    }
};

Object.defineProperty(Entities.World.prototype, "Mask", {
    get: function() {
        return this._mask;
    },
    set: function(mask) {
        this._mask = mask;
    }
});

Object.defineProperty(Entities.World.prototype, "Size", {
    get: function() {
        return this._size;
    },
    set: function(size) {
        this._size = size;
    }
});

Object.defineProperty(Entities.World.prototype, "Type", {
    get: function() {
        return this._type;
    },
    set: function(type) {
        this._type = type;
    }
});

Object.defineProperty(Entities.World.prototype, "ComponentType", {
    get: function() {
        return this._componentType;
    },
    set: function(componentType) {
        this._componentType = componentType;
    }
});<commit_msg>makes minor changes to world to enhance readability<commit_after>/**
* @author       Alan Smithee <ggnore.alan.smithee@gmail.com>
* @copyright    2015 GGNoRe.
* @license      {@link https://github.com/GGAlanSmithee/Entities/blob/master/LICENSE|MIT License}
*/

'use strict';

Entities.World = function(size, type) {
    this.ComponentType = {
        None : 0
    };

    this.Size = size ? size : 100;

    this.Type = type !== undefined ? type : Entities.World.Type.Static;

    this.Entities = [];

    for (var i = 0; i < this.Size; ++i) {
        this.Entities.push(this.ComponentType.None);
    }
};

Entities.World.Type = {
    Dynamic : 0,
    SemiDynamic : 1,
    Static : 2
};

Entities.World.prototype = {
    constructor : Entities.World,

    registerComponent : function(component) {
        var arr = [];

        for (var type in this.ComponentType) {
           if (this.ComponentType.hasOwnProperty(type)) {
                arr.push(this.ComponentType[type]);
            }
        }

        var max = Math.max.apply(null, arr);

        this.ComponentType[component.name] = max === undefined || max === null ? 0: max === 0 ? 1 : max * 2;

        if (this[component.name]) {
            return;
        }

        this[component.name] = [];

        if (this.Type === Entities.World.Type.Dynamic || this.Type === Entities.World.Type.SemiDynamic) {
            return;
        }

        for (var i = 0; i < this.Size; ++i) {
            this[component.name].push(new global[component.name]());
        }
    }
};

Object.defineProperty(Entities.World.prototype, "Entities", {
    get: function() {
        return this._entities;
    },
    set: function(entities) {
        this._entities = entities;
    }
});

Object.defineProperty(Entities.World.prototype, "Size", {
    get: function() {
        return this._size;
    },
    set: function(size) {
        this._size = size;
    }
});

Object.defineProperty(Entities.World.prototype, "Type", {
    get: function() {
        return this._type;
    },
    set: function(type) {
        this._type = type;
    }
});

Object.defineProperty(Entities.World.prototype, "ComponentType", {
    get: function() {
        return this._componentType;
    },
    set: function(componentType) {
        this._componentType = componentType;
    }
});<|endoftext|>