<commit_before>import React, {Component} from 'react';
import {
  StyleSheet,
  Dimensions,
  View
} from 'react-native';

import Pdf from 'react-native-pdf';

class PDFView extends Component {
  static displayName = 'PlayDetailView';

  static navigationOptions = ({navigation}) => ({
    title: `${navigation.state.params.title}`
  });

  constructor(props) {
    super(props);
    this.state = {
      page: 1,
      pageCount: 1
    };
    this.pdf = null;
  }

  render() {
    const {params} = this.props.navigation.state;
    let source = require('../cheatsheets/pinout/esp8266_devkit.pdf');  // ios only
    if (!__DEV__) {
      source = {uri: params.uri};
    }

    return (
      <View style={styles.container}>
        <Pdf ref={(pdf) => {this.pdf = pdf;}}
             source={source}
             page={1}
             scale={1}
             horizontal={false}
             onLoadComplete={(pageCount) => {
               this.setState({pageCount: pageCount});
               console.log(`total page count: ${pageCount}`);
             }}
             onPageChanged={(page) => {
               this.setState({page: page});
               console.log(`current page: ${page}`);
             }}
             onError={(error) => {
               console.log(error);
             }}
             style={styles.pdf}/>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'flex-start',
    alignItems: 'center',
    paddingBottom: 20
  },
  pdf: {
    flex: 1,
    marginLeft: 10,
    marginRight: 10,
    width: Dimensions.get('window').width
  }
});

export default PDFView;
<commit_msg>[PDFView] add count<commit_after>import React, {Component} from 'react';
import {
  StyleSheet,
  Dimensions,
  Text,
  View
} from 'react-native';

import Pdf from 'react-native-pdf';
const deviceWidth = Dimensions.get('window').width;

class PDFView extends Component {
  static displayName = 'PlayDetailView';

  static navigationOptions = ({navigation}) => ({
    title: `${navigation.state.params.title}`
  });

  constructor(props) {
    super(props);
    this.state = {
      page: 1,
      pageCount: 1
    };
    this.pdf = null;
  }

  render() {
    const {params} = this.props.navigation.state;
    let source = require('../cheatsheets/pinout/esp8266_devkit.pdf');  // ios only
    if (!__DEV__) {
      source = {uri: params.uri};
    }

    return (
      <View style={styles.container}>
        <Pdf ref={(pdf) => {this.pdf = pdf;}}
             source={source}
             page={1}
             scale={1}
             horizontal={false}
             onLoadComplete={(pageCount) => {
               this.setState({pageCount: pageCount});
               console.log(`total page count: ${pageCount}`);
             }}
             onPageChanged={(page) => {
               this.setState({page: page});
               console.log(`current page: ${page}`);
             }}
             onError={(error) => {
               console.log(error);
             }}
             style={styles.pdf}/>
        <View style={styles.pageTag}>
          <Text style={{color: '#384452'}}>{this.state.page} / {this.state.pageCount}</Text>
        </View>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'flex-start',
    alignItems: 'center',
    paddingBottom: 20
  },
  pdf: {
    flex: 1,
    marginLeft: 10,
    marginRight: 10,
    width: Dimensions.get('window').width
  },
  pageTag: {
    backgroundColor: 'transparent',
    position: 'absolute',
    flexDirection: 'row',
    marginRight: 10,
    marginTop: 10,
    paddingLeft: 10,
    paddingRight: 10,
    paddingTop: 5,
    paddingBottom: 5,
    borderRadius: 5,
    right: 0
  }
});

export default PDFView;
<|endoftext|>


<commit_before>BoxParser.vmhdBox.prototype.write = function(stream) {
	var i;
	this.version = 0;
	this.flags = 0;
	this.size = 8;
	this.writeHeader(stream);
	stream.writeUint16(this.graphicsmode);
	stream.writeUint16Array(this.opcolor);
}

<commit_msg>Fix #71<commit_after>BoxParser.vmhdBox.prototype.write = function(stream) {
	var i;
	this.version = 0;
	this.flags = 1;
	this.size = 8;
	this.writeHeader(stream);
	stream.writeUint16(this.graphicsmode);
	stream.writeUint16Array(this.opcolor);
}

<|endoftext|>


<commit_before>const React = require('react');
const ReactDOM = require('react-dom');
const utilities = require("../../../node_modules/simple-react-utilities/js/utilities.js");

import cardData from this.props.cardData;
import Filter from './filter.js';
import { Card } from './components/card.js';
import { CardGroup } from './components/card-group.js';
import { ShowHideButton } from './components/show-hide-button.js';

export class CardBook extends React.Component {
  /**
   * constructor for CardBook
   * @param  {object} props [element properties/attributes passed in at initialization]
   */
  constructor(props) {
    super(props);

    var sortedCardData = utilities.sortObjectsByProp(cardData, "name");

    this.state = {
      cards : sortedCardData,
      filters : []
    };

    this.resetState = this.resetState.bind(this);
    this.executeFilters = this.executeFilters.bind(this);
    this.addFilterToFilterGroup = this.addFilterToFilterGroup.bind(this);
    this.removeFilterFromFilterGroup = this.removeFilterFromFilterGroup.bind(this);
  }

  executeFilters(filters) {
    var _this = this;
    var cards = cardData;
    let filterArgs;

    for (let filter in filters) {
      filterArgs = filters[filter].filterArgs;

      if (filterArgs.length) {
        cards = filters[filter].filterFunc(filterArgs[0], cards); // run once to cut down to this filter

        for (let i = 1, l = filterArgs.length; i < l; i++) {
          cards = cards.concat(filters[filter].filterFunc(filterArgs[i],cardData)); // loop through cards to add back
        }
      }
    }

    cards = utilities.sortObjectsByProp(cards, "name");
    cards = utilities.arrayUnique(cards);

    if (!Array.isArray(cards)) {
      cards = [];
    }

    this.setState({
      cards : cards,
      filters : this.state.filters
    });
  }

  addFilterToFilterGroup(filterName,filterObject) {
    let filters = this.state.filters;
    filters[filterName] = filters[filterName] || {};
    filters[filterName].filterArgs = filters[filterName].filterArgs || [];

    // add the filter args and update the filter function
    filters[filterName].filterArgs.push(filterObject.filterArgs);
    filters[filterName].filterFunc = filterObject.filterFunc;

    // TODO: workaround for search filter
    if (filterName === 'search') {

      filters[filterName].filterArgs = [filterObject.filterArgs];
    }

    // save
    this.setState({
      cards : [],
      filters : filters[filterName]
    });

    console.log(this.state.filters);
    // update
    this.executeFilters(this.state.filters);
  }

  removeFilterFromFilterGroup(filterName,filter) {
    var filterArgsList;
    var removeIndex;

    if (this.state.filters[filterName]) {
      filterArgsList = this.state.filters[filterName].filterArgs;
      removeIndex = filterArgsList.indexOf(filter);

      filterArgsList.splice(removeIndex, 1);
    }

    this.setState({
      cards : this.state.cards,
      filters : Object.assign({},this.state.filters[filterName], filterArgsList)
    });

    this.executeFilters(this.state.filters);
  }

  resetState() {
    var sortedCardData = utilities.sortObjectsByProp(cardData, "name");

    this.setState({
      cards : sortedCardData,
      filters : []
    });
  }

  /**
   * puts everything in the DOM
   */
	render() {
    let i = 0;
    let j = 0;

    return

Cards ({this.state.cards.length})

                  {this.props.searchFilter(this.addFilterToFilterGroup, this.removeFilterFromFilterGroup)}

                    {this.props.filters.map((filterRender) => {
                      i++;
                      return
{filterRender(this.addFilterToFilterGroup, this.removeFilterFromFilterGroup)}
;
                    })}

Advanced Filters<ShowHideButton target={".advanced-filters"} showText="+" hideText="-" startClosed="true"/>

                    {this.props.advancedFilters.map((filterRender) => {
                      j++;
                      return
{filterRender(this.addFilterToFilterGroup, this.removeFilterFromFilterGroup)}
;
                    })}

                    <CardGroup cards={this.state.cards} />

;
	}
}
<commit_msg>get carddata from instance<commit_after>const React = require('react');
const ReactDOM = require('react-dom');
const utilities = require("../../../node_modules/simple-react-utilities/js/utilities.js");

import Filter from './filter.js';
import { Card } from './components/card.js';
import { CardGroup } from './components/card-group.js';
import { ShowHideButton } from './components/show-hide-button.js';

export class CardBook extends React.Component {
  /**
   * constructor for CardBook
   * @param  {object} props [element properties/attributes passed in at initialization]
   */
  constructor(props) {
    super(props);

    var sortedCardData = utilities.sortObjectsByProp(this.props.cardData, "name");

    this.state = {
      cards : sortedCardData,
      filters : []
    };

    this.resetState = this.resetState.bind(this);
    this.executeFilters = this.executeFilters.bind(this);
    this.addFilterToFilterGroup = this.addFilterToFilterGroup.bind(this);
    this.removeFilterFromFilterGroup = this.removeFilterFromFilterGroup.bind(this);
  }

  executeFilters(filters) {
    var _this = this;
    var cards = this.props.cardData;
    let filterArgs;

    for (let filter in filters) {
      filterArgs = filters[filter].filterArgs;

      if (filterArgs.length) {
        cards = filters[filter].filterFunc(filterArgs[0], cards); // run once to cut down to this filter

        for (let i = 1, l = filterArgs.length; i < l; i++) {
          cards = cards.concat(filters[filter].filterFunc(filterArgs[i],this.props.cardData)); // loop through cards to add back
        }
      }
    }

    cards = utilities.sortObjectsByProp(cards, "name");
    cards = utilities.arrayUnique(cards);

    if (!Array.isArray(cards)) {
      cards = [];
    }

    this.setState({
      cards : cards,
      filters : this.state.filters
    });
  }

  addFilterToFilterGroup(filterName,filterObject) {
    let filters = this.state.filters;
    filters[filterName] = filters[filterName] || {};
    filters[filterName].filterArgs = filters[filterName].filterArgs || [];

    // add the filter args and update the filter function
    filters[filterName].filterArgs.push(filterObject.filterArgs);
    filters[filterName].filterFunc = filterObject.filterFunc;

    // TODO: workaround for search filter
    if (filterName === 'search') {

      filters[filterName].filterArgs = [filterObject.filterArgs];
    }

    // save
    this.setState({
      cards : [],
      filters : filters[filterName]
    });

    console.log(this.state.filters);
    // update
    this.executeFilters(this.state.filters);
  }

  removeFilterFromFilterGroup(filterName,filter) {
    var filterArgsList;
    var removeIndex;

    if (this.state.filters[filterName]) {
      filterArgsList = this.state.filters[filterName].filterArgs;
      removeIndex = filterArgsList.indexOf(filter);

      filterArgsList.splice(removeIndex, 1);
    }

    this.setState({
      cards : this.state.cards,
      filters : Object.assign({},this.state.filters[filterName], filterArgsList)
    });

    this.executeFilters(this.state.filters);
  }

  resetState() {
    var sortedCardData = utilities.sortObjectsByProp(this.props.cardData, "name");

    this.setState({
      cards : sortedCardData,
      filters : []
    });
  }

  /**
   * puts everything in the DOM
   */
	render() {
    let i = 0;
    let j = 0;

    return

Cards ({this.state.cards.length})

                  {this.props.searchFilter(this.addFilterToFilterGroup, this.removeFilterFromFilterGroup)}

                    {this.props.filters.map((filterRender) => {
                      i++;
                      return
{filterRender(this.addFilterToFilterGroup, this.removeFilterFromFilterGroup)}
;
                    })}

Advanced Filters<ShowHideButton target={".advanced-filters"} showText="+" hideText="-" startClosed="true"/>

                    {this.props.advancedFilters.map((filterRender) => {
                      j++;
                      return
{filterRender(this.addFilterToFilterGroup, this.removeFilterFromFilterGroup)}
;
                    })}

                    <CardGroup cards={this.state.cards} />

;
	}
}
<|endoftext|>


<commit_before>import Koa from 'koa';

import vhost, {filterHost as filter} from '.';

describe('when filtering virtual hosts', () => {
  test('a non-string hostname should always match', () =>
    expect(filter()).toBeTruthy());

  test('when no virtual hosts are expected it should always match', () => {
    const reqHost = 'anything.server.my';
    expect(filter(null, reqHost)).toBeTruthy();
  });

  describe('by string', () => {
    const filterHost = 'yes.server.my';

    test('host should match when the strings match', () => {
      const reqHost = 'yes.server.my';
      expect(filter(filterHost, reqHost)).toBeTruthy();
    });

    test('host should not match when the strings do not match', () => {
      const reqHost = 'no.server.my';
      expect(filter(filterHost, reqHost)).toBeFalsy();
    });
  });

  describe('by regex', () => {
    const filterHost = /.*.server.my/;

    test('host should match when the regex matches', () => {
      const reqHost = 'regex.server.my';
      expect(filter(filterHost, reqHost)).toBeTruthy();
    });

    test('host should not match when the regex does not match', () => {
      const reqHost = 'regex.server.yours';
      expect(filter(filterHost, reqHost)).toBeFalsy();
    });
  });

  describe('by array', () => {
    const filterHosts = [];

    test('should always match when array is empty', () => {
      expect(filter(filterHosts, null)).toBeTruthy();
    });

    describe('when array is not empty', () => {
    const filterHosts = ['string.server.my'];

      test('host should match when at least one vhost matches', () => {
        const reqHost = 'string.server.my';
        expect(filter(filterHosts, reqHost)).toBeTruthy();
      });

      test('host should not match when no vhost matches', () => {
        const reqHost = 'string.server.theirs';
        expect(filter(filterHosts, reqHost)).toBeFalsy();
      });
    });
  });
});

describe('virtual host middleware', () => {
  const next = () => new Promise(() => {
    // empty resolver
  });
  let ctx = {};

  beforeEach(() => {
    ctx = {};
  });

  test('should defer to other middleware when no domain is passed', () => {
    const vhostMw = vhost();
    const afterVhost = vhostMw(ctx, next);
    expect(afterVhost).toBeInstanceOf(Promise);
  });

  test('should defer to other middleware when the domain matches', () => {
    ctx.hostname = 'actual.domain.my';

    const vhostMw = vhost('actual.domain.my');
    const afterVhost = vhostMw(ctx, next);
    expect(afterVhost).toBeInstanceOf(Promise);
  });

  test('should not defer to other middleware when the domain does not match', () => {
    ctx.hostname = 'nonexistent.domain.my';

    const vhostMw = vhost('actual.domain.my');
    const afterVhost = vhostMw(ctx, next);
    expect(afterVhost).not.toBeInstanceOf(Promise);
  });
});
<commit_msg>Stopped importing koa in the vhost tests now that it is not necessary anymore<commit_after>import vhost, {filterHost as filter} from '.';

describe('when filtering virtual hosts', () => {
  test('a non-string hostname should always match', () =>
    expect(filter()).toBeTruthy());

  test('when no virtual hosts are expected it should always match', () => {
    const reqHost = 'anything.server.my';
    expect(filter(null, reqHost)).toBeTruthy();
  });

  describe('by string', () => {
    const filterHost = 'yes.server.my';

    test('host should match when the strings match', () => {
      const reqHost = 'yes.server.my';
      expect(filter(filterHost, reqHost)).toBeTruthy();
    });

    test('host should not match when the strings do not match', () => {
      const reqHost = 'no.server.my';
      expect(filter(filterHost, reqHost)).toBeFalsy();
    });
  });

  describe('by regex', () => {
    const filterHost = /.*.server.my/;

    test('host should match when the regex matches', () => {
      const reqHost = 'regex.server.my';
      expect(filter(filterHost, reqHost)).toBeTruthy();
    });

    test('host should not match when the regex does not match', () => {
      const reqHost = 'regex.server.yours';
      expect(filter(filterHost, reqHost)).toBeFalsy();
    });
  });

  describe('by array', () => {
    const filterHosts = [];

    test('should always match when array is empty', () => {
      expect(filter(filterHosts, null)).toBeTruthy();
    });

    describe('when array is not empty', () => {
    const filterHosts = ['string.server.my'];

      test('host should match when at least one vhost matches', () => {
        const reqHost = 'string.server.my';
        expect(filter(filterHosts, reqHost)).toBeTruthy();
      });

      test('host should not match when no vhost matches', () => {
        const reqHost = 'string.server.theirs';
        expect(filter(filterHosts, reqHost)).toBeFalsy();
      });
    });
  });
});

describe('virtual host middleware', () => {
  const next = () => new Promise(() => {
    // empty resolver
  });
  let ctx = {};

  beforeEach(() => {
    ctx = {};
  });

  test('should defer to other middleware when no domain is passed', () => {
    const vhostMw = vhost();
    const afterVhost = vhostMw(ctx, next);
    expect(afterVhost).toBeInstanceOf(Promise);
  });

  test('should defer to other middleware when the domain matches', () => {
    ctx.hostname = 'actual.domain.my';

    const vhostMw = vhost('actual.domain.my');
    const afterVhost = vhostMw(ctx, next);
    expect(afterVhost).toBeInstanceOf(Promise);
  });

  test('should not defer to other middleware when the domain does not match', () => {
    ctx.hostname = 'nonexistent.domain.my';

    const vhostMw = vhost('actual.domain.my');
    const afterVhost = vhostMw(ctx, next);
    expect(afterVhost).not.toBeInstanceOf(Promise);
  });
});
<|endoftext|>


<commit_before>$(function () {
    var upview = $('#uploadview')
    var downview = $('#downloadview')
    var previewimg = $('#previewimg')
    var previewtext = $('#previewtext')
    var previewfilename = $('#filename')
    var details = $('#downloaddetails')

    var dlbtn = $('#dlbtn')
    var deletebtn = $('#deletebtn')
    var viewbtn = $('#inbrowserbtn')

    function hashchanged() {
        if (window.location.hash && window.location.hash != '#') {
            upview.addClass('hidden')
            previewtext.addClass('hidden')
            previewimg.addClass('hidden')
            downview.removeClass('hidden')
            deletebtn.hide()

            var seed = window.location.hash.substring(1)

            function embed(data) {

                previewfilename.text(data.header.name)

                var url = URL.createObjectURL(data.decrypted)

                viewbtn.prop('href', url)
                dlbtn.prop('href', url)
                dlbtn.prop('download', data.header.name)

                if (data.header.mime.startsWith('image/')) {
                    previewimg.prop('src', url)
                    previewimg.removeClass('hidden')
                } else if (data.header.mime.startsWith('text/')) {
                    var fr = new FileReader()

                    fr.onload = function () {

                        var text = fr.result

                        previewtext.removeClass('hidden')
                        previewtext.find('code').text(text)
                        hljs.highlightBlock(previewtext.find('code')[0])
                    }
                    fr.readAsText (data.decrypted)
                } else if (data.header.mime.startsWith('video/')) {
                    details.find('video.preview').removeClass('hidden').prop('src', url)
                } else if (data.header.mime.startsWith('audio/')) {
                    details.find('audio.preview').removeClass('hidden').prop('src', url)
                } else {
                    // Unknown, todo
                }
                $('#downloadprogress').text('').hide()
                details.removeClass('hidden')
            }

            function downloaded() {
                $('#downloadprogress').text('Decrypting')
                crypt.decrypt(this.response, seed).done(embed)
            }

            function downloadprogress(e) {
                var percent = (e.loaded / e.total) * 100
                $('#downloadprogress').text(Math.floor(percent) + '%')
            }

            function downloadfromident(ident) {

                var stored = localStorage.getItem('delete-' + seed)

                if (stored) {
                    deletebtn.show().prop('href', (g.config.server ? g.config.server : '') + 'del?delkey=' + stored + '&ident=' + ident.ident)
                }

                var xhr = new XMLHttpRequest();
                xhr.onload = downloaded
                xhr.open('GET', (g.config.server ? g.config.server : '') + 'i/' + ident.ident)
                xhr.responseType = 'blob'

                xhr.addEventListener('progress', downloadprogress, false)
                xhr.send()
            }

            details.find('.preview').addClass('hidden')
            details.find('video.preview').prop('src', '')
            details.find('audio.preview').prop('src', '')
            previewimg.prop('src', '')
            previewtext.find('code').empty()
            details.addClass('hidden')
            upview.addClass('hidden')
            $('#downloadprogress').show().text('Loading')

            crypt.ident(seed).done(downloadfromident)
        } else {
            upview.removeClass('hidden')
            details.find('.preview').addClass('hidden')
            details.addClass('hidden')
            downview.addClass('hidden')
            details.find('video.preview').prop('src', '')
            details.find('audio.preview').prop('src', '')
            previewimg.prop('src', '')
            previewtext.find('code').empty()
            g.focusPaste()
        }
    }

    $(window).on('hashchange', hashchanged)
    hashchanged();

});
<commit_msg>Handle error in a cheap way<commit_after>$(function () {
    var upview = $('#uploadview')
    var downview = $('#downloadview')
    var previewimg = $('#previewimg')
    var previewtext = $('#previewtext')
    var previewfilename = $('#filename')
    var details = $('#downloaddetails')

    var dlbtn = $('#dlbtn')
    var deletebtn = $('#deletebtn')
    var viewbtn = $('#inbrowserbtn')

    function hashchanged() {
        if (window.location.hash && window.location.hash != '#') {
            upview.addClass('hidden')
            previewtext.addClass('hidden')
            previewimg.addClass('hidden')
            downview.removeClass('hidden')
            deletebtn.hide()

            var seed = window.location.hash.substring(1)

            function embed(data) {

                previewfilename.text(data.header.name)

                var url = URL.createObjectURL(data.decrypted)

                viewbtn.prop('href', url)
                dlbtn.prop('href', url)
                dlbtn.prop('download', data.header.name)

                if (data.header.mime.startsWith('image/')) {
                    previewimg.prop('src', url)
                    previewimg.removeClass('hidden')
                } else if (data.header.mime.startsWith('text/')) {
                    var fr = new FileReader()

                    fr.onload = function () {

                        var text = fr.result

                        previewtext.removeClass('hidden')
                        previewtext.find('code').text(text)
                        hljs.highlightBlock(previewtext.find('code')[0])
                    }
                    fr.readAsText (data.decrypted)
                } else if (data.header.mime.startsWith('video/')) {
                    details.find('video.preview').removeClass('hidden').prop('src', url)
                } else if (data.header.mime.startsWith('audio/')) {
                    details.find('audio.preview').removeClass('hidden').prop('src', url)
                } else {
                    // Unknown, todo
                }
                $('#downloadprogress').text('').hide()
                details.removeClass('hidden')
            }

            function downloaded() {
                $('#downloadprogress').text('Decrypting')
                crypt.decrypt(this.response, seed).done(embed)
            }

            function downloadprogress(e) {
                var percent = (e.loaded / e.total) * 100
                $('#downloadprogress').text(Math.floor(percent) + '%')
            }

            function failed() {
                window.location = '#'
            }

            function downloadfromident(ident) {

                var stored = localStorage.getItem('delete-' + seed)

                if (stored) {
                    deletebtn.show().prop('href', (g.config.server ? g.config.server : '') + 'del?delkey=' + stored + '&ident=' + ident.ident)
                }

                var xhr = new XMLHttpRequest()
                xhr.onload = downloaded
                xhr.open('GET', (g.config.server ? g.config.server : '') + 'i/' + ident.ident)
                xhr.responseType = 'blob'
                xhr.onerror = failed
                xhr.addEventListener('progress', downloadprogress, false)
                xhr.send()
            }

            details.find('.preview').addClass('hidden')
            details.find('video.preview').prop('src', '')
            details.find('audio.preview').prop('src', '')
            previewimg.prop('src', '')
            previewtext.find('code').empty()
            details.addClass('hidden')
            upview.addClass('hidden')
            $('#downloadprogress').show().text('Loading')

            crypt.ident(seed).done(downloadfromident)
        } else {
            upview.removeClass('hidden')
            details.find('.preview').addClass('hidden')
            details.addClass('hidden')
            downview.addClass('hidden')
            details.find('video.preview').prop('src', '')
            details.find('audio.preview').prop('src', '')
            previewimg.prop('src', '')
            previewtext.find('code').empty()
            g.focusPaste()
        }
    }

    $(window).on('hashchange', hashchanged)
    hashchanged();

});
<|endoftext|>


<commit_before>var mouseState = false;
document.onmousedown = function(e) {
    mouseState = true;
}
document.onmouseup = function(e) {
    mouseState = false;
}

function flushThis(id){
   var msie = 'Microsoft Internet Explorer';
   var tmp = 0;
   var elementOnShow = document.getElementById(id);
   if (navigator.appName == msie){
      tmp = elementOnShow.parentNode.offsetTop  +  'px';
   } else {
      tmp = elementOnShow.offsetTop;
   }
}

function applyClass(klass) {

    /*
       Checks all the table elements,
       if they are selected, it removes the
       selected class (and all other classes)
       and applies the passed in class
    */

    $("#holiday-table")
        .find("td")
        .each(function () {
            if ($(this).hasClass("selected")) {
                $(this).removeClass();
                $(this).addClass(klass);
            }
        });
    return true;
}

function submit_all() {

    /*
       Submits all entries on the form

       Takes no parameters and returns true/false
       depending on success.
    */

    var successfully_completed = false;
    $("#holiday-table")
        .find(":button")
        .not("#submit_all, #btn_change_td")
        .each(function () {
            successfully_completed = submit_holidays($(this).attr("user_id"), true)
        });
    // refresh the table data
    setTimeout("change_table_data()", 1000);
    return successfully_completed;
}

function submit_holidays(user_id, mass) {
    /*
       En masse changes a set of holidays and
       takes a user_id as a parameter.

       Mass is true/false, if true it

       Returns true for success, false for error
    */

    if (!user_id) {
        return true;
    }

    // create a map to hold the holidays
    var holiday_map = JSON;

    // iterate through the table and check if it's
    // selected or not, if it's selected, ignore it.
    // else, add the number and the class to the map.
    $("#holiday-table")
        .find("td[usrid='"+user_id+"']")
        .each(function () {
            // remove the selected class off the element
            $(this).removeClass("selected");
            // get the bg colour of the td
            var current_class = $(this).attr('class');
            // this check is redundant but it helps if there
            // are any changes to the selection methods
            if (current_class !== "selected") {
                holiday_map[$(this).text()] = current_class;
            }
        });

    // setup our ajax properties
    $.ajaxSetup({
        type: 'POST',
        dataType: 'json'
    });

    $.ajax({
        url: '/ajax/',
        data: {
            'form_type': 'mass_holidays',
            'year': $("#holiday-table").attr("year"), // from the table header
            'month': $("#holiday-table").attr("month"),
            'holiday_data': JSON.stringify(holiday_map),
            'user_id': user_id
        },
        success: function(data) {
            if (data.success === true) {
                if (!mass) {
                    alert("Holidays updated successfully");
                }
            } else {
                alert(data.error);
            }
        },
        error: function(ajaxObj, textStatus, error) {
            alert(error);
        }
    });

    // return true so programmatic callers can
    // see we've completed
    return true;
}

function addFunctions () {

    "use strict";

    $("#holiday-table")
        .find(".job_code").each( function () {
            if ( $("#is_team_leader").attr("value") ) {
                $(this).text('');
            }
        });

    // all the daytype classes
    // are assigned a click handler which
    // swaps the colour depending on what
    // it currently is.
    $("#holiday-table")
        .find('.empty, .DAYOD, .TRAIN, '
            + '.WKDAY, .SICKD, .HOLIS, '
            + '.SPECI, .MEDIC, .PUABS, '
            + '.PUWRK, .SATUR, .RETRN, '
            + '.WKHOM, .OTHER, .ROVER  ')
        .not(":button")
        .attr("unselectable", "on")   // make it so you can't select text
        .mouseover(function (e) {
            if (mouseState) {

                if ($(this).hasClass("selected")) {
                    $(this).removeClass("selected");
                } else {
                    $(this).addClass("selected");
                }
                e.preventDefault();
                e.stopPropagation();
            }
        })
        .mousedown(function (e) {
            if ($(this).hasClass("selected")) {
                $(this).removeClass("selected");
            } else {
                $(this).addClass("selected");
            }
        });

    $("#year_select").val($("#holiday-table").attr("year"));
    $("#month_select").val($("#holiday-table").attr("month"));
    $("#process_select").val($("#holiday-table").attr("process"));
    $("#employees-select, #day_options").change(function () {
        retrieveComments();
    });
    $("#year_select, #month_select, #process_select").change(function () {
        change_table_data();
    });

    $("#holiday-table")
        .attr("border", "1")

    return true;
}

function change_table_data () {

    "use strict";

    /*
       Function which takes the values of the select boxes
       constructs an ajax call based on those and replaces
       the table with the data returned from the ajax call
    */

    var year = $("#year_select").val();
    var month = $("#month_select").val();
    var process = $("#process_select").val();

    if (process === "ALL") {
        process = "";
    }

    $.ajax({
        type: "GET",
        dataType: "HTML",
        url: "/holiday_planning/" + year + "/" + month + "/" + process,
        success: function(data) {

            $("#holiday-wrapper, #comments-wrapper").fadeTo(500, 0, function() {
                if ( $("#isie").attr("isie") === "true" ) {
                    $("#comments-wrapper").load(
                        "/holiday_planning/" + year + "/" + month + " #com-field"
                    );
                    $("#holiday-wrapper").load(
                        "/holiday_planning/" + year + "/" + month + " #holiday-table",
                        function() {
                            addFunctions();
                            retrieveComments();
                        }
                    );
                } else {
                    var holiday_html = $(data).find("#holiday-wrapper").html();
                    var comments_html = $(data).find("#comments-wrapper").html();
                    var table_year = $(data).find("#holiday-table").attr("year");
                    var table_month = $(data).find("#holiday-table").attr("month");

                    $("#com-field").html(comments_html);
                    $("#holiday-table").html(holiday_html);
                }
                flushThis("holiday-wrapper");
                $("#holiday-table").attr("year", table_year);
                $("#holiday-table").attr("month", table_month);
                addFunctions();
                $("#year_select").val(year);
                $("#month_select").val(month);
                $("#process_select").val(process);
                $("#holiday-wrapper, #comments-wrapper").fadeTo(500, 1);
            });
            checkTeamLeader();
        }
    });
    return true;
}

function removeComment() {
    "use strict";

    /*
      Function which removes a comment from the database for a specific
      tracking entry.
    */

    $.ajaxSetup({
        type: "POST",
        dataType: "json"
    });

    $.ajax({
        url: '/ajax/',
        data: {
            form_type: 'remove_comment',
            year: $("#holiday-table").attr("year"),
            month: $("#holiday-table").attr("month"),
            user: $("#employees-select").val(),
            day: $("#day_options").val()
        },
        success: function (data) {
            if (data.success) {
                retrieveComments();
                change_table_data();
            } else {
                alert(data.error)
            }
        },
        error: function (data) {
            alert(data.error);
        }
    });

}

function insertComment() {

    "use strict";

    /*
      Function which inserts a comment into the database for a specific
      tracking entry.
    */

    $.ajaxSetup({
        type: "POST",
        dataType: "json"
    });

    $.ajax({
        url: '/ajax/',
        data: {
            form_type: 'add_comment',
            year: $("#holiday-table").attr("year"),
            month: $("#holiday-table").attr("month"),
            user: $("#employees-select").val(),
            day: $("#day_options").val(),
            comment: $("#comments-field-comment").val()
        },
        success: function (data) {
            if (data.success) {
                retrieveComments();
                change_table_data();
            } else {
                alert(data.error)
            }
        },
        error: function (data) {
            alert(data.error);
        }
    });

}

function retrieveComments() {

    "use strict";

    /*
      Function which retrieves the comment associated with a tracking entry,
      this allows managers to apply a comment onto a field and edit the
      comments that they have already added onto a field by selecting the
      dates that they used it on.
    */

    $.ajaxSetup({
        type: "GET",
        dataType: "json"
    });

    $("#comments-field-comment").val('');

    $.ajax({
        url: '/ajax/',
        data: {
            form_type: 'get_comments',
            year: $("#holiday-table").attr("year"),
            month: $("#holiday-table").attr("month"),
            user: $("#employees-select").val(),
            day: $("#day_options").val()
        },
        success: function (data) {
            if (data.success) {
                $("#comments-field-comment").val(data.comment);
            } else {
                alert(data.error)
            }
        },
        error: function(data) {
            alert(data.error);
        }
    });

    return true;

}

function checkTeamLeader() {

    /*
      Function which checks if the user is a team leader.

      If so, the field is removed
    */

    "use strict";

    var is_team_leader = $("#is_team_leader").attr("value");

    $("#holiday-table")
        .find(".job_code").each( function () {
            if ( is_team_leader ) {
                $(this).text('');
            }
            $(this).css("color", "black")
        });

    return true;
}

$(function () {
    addFunctions();
    checkTeamLeader();
});
<commit_msg>HTML Element selector name change.<commit_after>var mouseState = false;
document.onmousedown = function(e) {
    mouseState = true;
}
document.onmouseup = function(e) {
    mouseState = false;
}

function flushThis(id){
   var msie = 'Microsoft Internet Explorer';
   var tmp = 0;
   var elementOnShow = document.getElementById(id);
   if (navigator.appName == msie){
      tmp = elementOnShow.parentNode.offsetTop  +  'px';
   } else {
      tmp = elementOnShow.offsetTop;
   }
}

function applyClass(klass) {

    /*
       Checks all the table elements,
       if they are selected, it removes the
       selected class (and all other classes)
       and applies the passed in class
    */

    $("#holiday-table")
        .find("td")
        .each(function () {
            if ($(this).hasClass("selected")) {
                $(this).removeClass();
                $(this).addClass(klass);
            }
        });
    return true;
}

function submit_all() {

    /*
       Submits all entries on the form

       Takes no parameters and returns true/false
       depending on success.
    */

    var successfully_completed = false;
    $("#holiday-table")
        .find(":button")
        .not("#submit_all, #btn_change_td")
        .each(function () {
            successfully_completed = submit_holidays($(this).attr("user_id"), true)
        });
    // refresh the table data
    setTimeout("change_table_data()", 1000);
    return successfully_completed;
}

function submit_holidays(user_id, mass) {
    /*
       En masse changes a set of holidays and
       takes a user_id as a parameter.

       Mass is true/false, if true it

       Returns true for success, false for error
    */

    if (!user_id) {
        return true;
    }

    // create a map to hold the holidays
    var holiday_map = JSON;

    // iterate through the table and check if it's
    // selected or not, if it's selected, ignore it.
    // else, add the number and the class to the map.
    $("#holiday-table")
        .find("td[usrid='"+user_id+"']")
        .each(function () {
            // remove the selected class off the element
            $(this).removeClass("selected");
            // get the bg colour of the td
            var current_class = $(this).attr('class');
            // this check is redundant but it helps if there
            // are any changes to the selection methods
            if (current_class !== "selected") {
                holiday_map[$(this).text()] = current_class;
            }
        });

    // setup our ajax properties
    $.ajaxSetup({
        type: 'POST',
        dataType: 'json'
    });

    $.ajax({
        url: '/ajax/',
        data: {
            'form_type': 'mass_holidays',
            'year': $("#holiday-table").attr("year"), // from the table header
            'month': $("#holiday-table").attr("month"),
            'holiday_data': JSON.stringify(holiday_map),
            'user_id': user_id
        },
        success: function(data) {
            if (data.success === true) {
                if (!mass) {
                    alert("Holidays updated successfully");
                }
            } else {
                alert(data.error);
            }
        },
        error: function(ajaxObj, textStatus, error) {
            alert(error);
        }
    });

    // return true so programmatic callers can
    // see we've completed
    return true;
}

function addFunctions () {

    "use strict";

    $("#holiday-table")
        .find(".job_code").each( function () {
            if ( $("#is_team_leader").attr("value") ) {
                $(this).text('');
            }
        });

    // all the daytype classes
    // are assigned a click handler which
    // swaps the colour depending on what
    // it currently is.
    $("#holiday-table")
        .find('.empty, .DAYOD, .TRAIN, '
            + '.WKDAY, .SICKD, .HOLIS, '
            + '.SPECI, .MEDIC, .PUABS, '
            + '.PUWRK, .SATUR, .RETRN, '
            + '.WKHOM, .OTHER, .ROVER  ')
        .not(":button")
        .attr("unselectable", "on")   // make it so you can't select text
        .mouseover(function (e) {
            if (mouseState) {

                if ($(this).hasClass("selected")) {
                    $(this).removeClass("selected");
                } else {
                    $(this).addClass("selected");
                }
                e.preventDefault();
                e.stopPropagation();
            }
        })
        .mousedown(function (e) {
            if ($(this).hasClass("selected")) {
                $(this).removeClass("selected");
            } else {
                $(this).addClass("selected");
            }
        });

    $("#year_select").val($("#holiday-table").attr("year"));
    $("#month_select").val($("#holiday-table").attr("month"));
    $("#process_select").val($("#holiday-table").attr("process"));
    $("#employees-select, #day_options").change(function () {
        retrieveComments();
    });
    $("#year_select, #month_select, #process_select").change(function () {
        change_table_data();
    });

    $("#holiday-table")
        .attr("border", "1")

    return true;
}

function change_table_data () {

    "use strict";

    /*
       Function which takes the values of the select boxes
       constructs an ajax call based on those and replaces
       the table with the data returned from the ajax call
    */

    var year = $("#year_select").val();
    var month = $("#month_select").val();
    var process = $("#process_select").val();

    if (process === "ALL") {
        process = "";
    }

    $.ajax({
        type: "GET",
        dataType: "HTML",
        url: "/holiday_planning/" + year + "/" + month + "/" + process,
        success: function(data) {

            $("#holiday-wrapper, #comments-wrapper").fadeTo(500, 0, function() {
                if ( $("#isie").attr("isie") === "true" ) {
                    $("#comments-wrapper").load(
                        "/holiday_planning/" + year + "/" + month + " #com-field"
                    );
                    $("#holiday-wrapper").load(
                        "/holiday_planning/" + year + "/" + month + " #holiday-table",
                        function() {
                            addFunctions();
                            retrieveComments();
                        }
                    );
                } else {
                    var holiday_html = $(data).find("#holiday-wrapper").html();
                    var comments_html = $(data).find("#comments-wrapper").html();
                    var table_year = $(data).find("#holiday-table").attr("year");
                    var table_month = $(data).find("#holiday-table").attr("month");

                    $("#com-field").html(comments_html);
                    $("#holiday-table").html(holiday_html);
                }
                flushThis("holiday-wrapper");
                $("#holiday-table").attr("year", table_year);
                $("#holiday-table").attr("month", table_month);
                addFunctions();
                $("#year_select").val(year);
                $("#month_select").val(month);
                $("#process_select").val(process);
                $("#holiday-wrapper, #comments-wrapper").fadeTo(500, 1);
            });
            checkTeamLeader();
        }
    });
    return true;
}

function removeComment() {
    "use strict";

    /*
      Function which removes a comment from the database for a specific
      tracking entry.
    */

    $.ajaxSetup({
        type: "POST",
        dataType: "json"
    });

    $.ajax({
        url: '/ajax/',
        data: {
            form_type: 'remove_comment',
            year: $("#holiday-table").attr("year"),
            month: $("#holiday-table").attr("month"),
            user: $("#employees-select").val(),
            day: $("#day_options").val()
        },
        success: function (data) {
            if (data.success) {
                retrieveComments();
                change_table_data();
            } else {
                alert(data.error)
            }
        },
        error: function (data) {
            alert(data.error);
        }
    });

}

function insertComment() {

    "use strict";

    /*
      Function which inserts a comment into the database for a specific
      tracking entry.
    */

    $.ajaxSetup({
        type: "POST",
        dataType: "json"
    });

    $.ajax({
        url: '/ajax/',
        data: {
            form_type: 'add_comment',
            year: $("#holiday-table").attr("year"),
            month: $("#holiday-table").attr("month"),
            user: $("#user_select").val(),
            day: $("#day_options").val(),
            comment: $("#comments-field-comment").val()
        },
        success: function (data) {
            if (data.success) {
                retrieveComments();
                change_table_data();
            } else {
                alert(data.error)
            }
        },
        error: function (data) {
            alert(data.error);
        }
    });

}

function retrieveComments() {

    "use strict";

    /*
      Function which retrieves the comment associated with a tracking entry,
      this allows managers to apply a comment onto a field and edit the
      comments that they have already added onto a field by selecting the
      dates that they used it on.
    */

    $.ajaxSetup({
        type: "GET",
        dataType: "json"
    });

    $("#comments-field-comment").val('');

    $.ajax({
        url: '/ajax/',
        data: {
            form_type: 'get_comments',
            year: $("#holiday-table").attr("year"),
            month: $("#holiday-table").attr("month"),
            user: $("#employees-select").val(),
            day: $("#day_options").val()
        },
        success: function (data) {
            if (data.success) {
                $("#comments-field-comment").val(data.comment);
            } else {
                alert(data.error)
            }
        },
        error: function(data) {
            alert(data.error);
        }
    });

    return true;

}

function checkTeamLeader() {

    /*
      Function which checks if the user is a team leader.

      If so, the field is removed
    */

    "use strict";

    var is_team_leader = $("#is_team_leader").attr("value");

    $("#holiday-table")
        .find(".job_code").each( function () {
            if ( is_team_leader ) {
                $(this).text('');
            }
            $(this).css("color", "black")
        });

    return true;
}

$(function () {
    addFunctions();
    checkTeamLeader();
});
<|endoftext|>


<commit_before>import $ from "jquery";

import render_markdown_help from "../templates/markdown_help.hbs";

import * as browser_history from "./browser_history";
import * as common from "./common";
import * as components from "./components";
import {$t, $t_html} from "./i18n";
import * as keydown_util from "./keydown_util";
import * as markdown from "./markdown";
import * as overlays from "./overlays";
import * as popovers from "./popovers";
import * as rendered_markdown from "./rendered_markdown";
import * as ui from "./ui";
import * as util from "./util";

// Make it explicit that our toggler is undefined until
// set_up_toggler is called.
export let toggler;

const markdown_help_rows = [
    {
        markdown: "*italic*",
        usage_html: "(or Ctrl+I)",
    },
    {
        markdown: "**bold**",
        usage_html: "(or Ctrl+B)",
    },
    {
        markdown: "~~strikethrough~~",
    },
    {
        markdown: "[Zulip website](https://zulip.org)",
        usage_html: "(or Ctrl+Shift+L)",
    },
    {
        markdown: `\
* Milk
* Tea
  * Green tea
  * Black tea
  * Oolong tea
* Coffee`,
    },
    {
        markdown: `\
1. Milk
1. Tea
1. Coffee`,
    },
    {
        markdown: ":heart:",
        usage_html:
            '(and many others, from the Noto Project)',
    },
    {
        markdown: "@**Joe Smith**",
        usage_html: "(autocompletes from @joe)",
        output_html: '
@Joe Smith
',
        effect_html: "(notifies Joe Smith)",
    },
    {
        markdown: "@_**Joe Smith**",
        usage_html: "(autocompletes from @_joe)",
        output_html: '
Joe Smith
',
        effect_html: "(links to profile but doesn't notify Joe Smith)",
    },
    {
        markdown: "@**all**",
        effect_html: "(notifies all recipients)",
    },
    {
        markdown: "#**streamName**",
        output_html: "
#streamName
",
        effect_html: "(links to a stream)",
    },
    {
        markdown: "/me is busy working",
        output_html: '
Iago is busy working
',
        usage_html: "(send a status message as user Iago)",
    },
    {
        markdown: "Some inline `code`",
    },
    {
        markdown: `\
\`\`\`
def zulip():
    print "Zulip"
\`\`\``,
    },
    {
        markdown: `\
\`\`\`python
def zulip():
    print "Zulip"
\`\`\``,
        output_html: `\

def zulip():
    print "Zulip"

`,
    },
    {
        note_html: $t_html(
            {
                defaultMessage:
                    "To add syntax highlighting to a multi-line code block, add the language's first <z-link>Pygments short name</z-link> after the first set of back-ticks. You can also make a code block by indenting each line with 4 spaces.",
            },
            {
                "z-link": (content_html) =>
                    `<a target="_blank" rel="noopener noreferrer" href="https://pygments.org/docs/lexers/">${content_html}</a>`,
            },
        ),
    },
    {
        markdown: "> Quoted",
    },
    {
        markdown: `\
\`\`\`quote
Quoted block
\`\`\``,
    },
    {
        markdown: `\
\`\`\`spoiler Always visible heading
This text won't be visible until the user clicks.
\`\`\``,
    },
    {
        markdown: "Some inline math $$ e^{i \\pi} + 1 = 0 $$",
    },
    {
        markdown: `\
\`\`\`math
\\int_{0}^{1} f(x) dx
\`\`\``,
    },
    {
        note_html: $t_html(
            {
                defaultMessage:
                    "You can also make <z-link>tables</z-link> with this <z-link>Markdown-ish table syntax</z-link>.",
            },
            {
                "z-link": (content_html) =>
                    `<a target="_blank" rel="noopener noreferrer" href="https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#wiki-tables">${content_html}</a>`,
            },
        ),
    },
];

export function set_up_toggler() {
    for (const row of markdown_help_rows) {
        if (row.markdown && !row.output_html) {
            const message = {raw_content: row.markdown};
            markdown.apply_markdown(message);
            row.output_html = util.clean_user_content_links(message.content);
        }
    }

    const $markdown_help = $(render_markdown_help({markdown_help_rows}));
    $markdown_help.find(".rendered_markdown").each(function () {
        rendered_markdown.update_elements($(this));
    });
    $(".informational-overlays .overlay-body").append($markdown_help);

    const opts = {
        selected: 0,
        child_wants_focus: true,
        values: [
            {label: $t({defaultMessage: "Keyboard shortcuts"}), key: "keyboard-shortcuts"},
            {label: $t({defaultMessage: "Message formatting"}), key: "message-formatting"},
            {label: $t({defaultMessage: "Search operators"}), key: "search-operators"},
        ],
        callback(name, key) {
            $(".overlay-modal").hide();
            $(`#${CSS.escape(key)}`).show();
            ui.get_scroll_element($(`#${CSS.escape(key)}`).find(".modal-body")).trigger("focus");
        },
    };

    toggler = components.toggle(opts);
    const elem = toggler.get();
    elem.addClass("large allow-overflow");

    const modals = opts.values.map((item) => {
        const key = item.key; // e.g. message-formatting
        const modal = $(`#${CSS.escape(key)}`).find(".modal-body");
        return modal;
    });

    for (const modal of modals) {
        ui.get_scroll_element(modal).prop("tabindex", 0);
        keydown_util.handle({
            elem: modal,
            handlers: {
                ArrowLeft: toggler.maybe_go_left,
                ArrowRight: toggler.maybe_go_right,
            },
        });
    }

    $(".informational-overlays .overlay-tabs").append(elem);

    common.adjust_mac_shortcuts(".hotkeys_table .hotkey kbd");
    common.adjust_mac_shortcuts("#markdown-instructions kbd");
}

export function show(target) {
    if (!toggler) {
        set_up_toggler();
    }

    const overlay = $(".informational-overlays");

    if (!overlay.hasClass("show")) {
        overlays.open_overlay({
            name: "informationalOverlays",
            overlay,
            on_close() {
                browser_history.exit_overlay();
            },
        });
    }

    if (target) {
        toggler.goto(target);
    }
}

export function maybe_show_keyboard_shortcuts() {
    if (overlays.is_active()) {
        return;
    }
    if (popovers.any_active()) {
        return;
    }
    show("keyboard-shortcuts");
}
<commit_msg>info_overlay: Remove dead code.<commit_after>import $ from "jquery";

import render_markdown_help from "../templates/markdown_help.hbs";

import * as browser_history from "./browser_history";
import * as common from "./common";
import * as components from "./components";
import {$t, $t_html} from "./i18n";
import * as keydown_util from "./keydown_util";
import * as markdown from "./markdown";
import * as overlays from "./overlays";
import * as rendered_markdown from "./rendered_markdown";
import * as ui from "./ui";
import * as util from "./util";

// Make it explicit that our toggler is undefined until
// set_up_toggler is called.
export let toggler;

const markdown_help_rows = [
    {
        markdown: "*italic*",
        usage_html: "(or Ctrl+I)",
    },
    {
        markdown: "**bold**",
        usage_html: "(or Ctrl+B)",
    },
    {
        markdown: "~~strikethrough~~",
    },
    {
        markdown: "[Zulip website](https://zulip.org)",
        usage_html: "(or Ctrl+Shift+L)",
    },
    {
        markdown: `\
* Milk
* Tea
  * Green tea
  * Black tea
  * Oolong tea
* Coffee`,
    },
    {
        markdown: `\
1. Milk
1. Tea
1. Coffee`,
    },
    {
        markdown: ":heart:",
        usage_html:
            '(and many others, from the Noto Project)',
    },
    {
        markdown: "@**Joe Smith**",
        usage_html: "(autocompletes from @joe)",
        output_html: '
@Joe Smith
',
        effect_html: "(notifies Joe Smith)",
    },
    {
        markdown: "@_**Joe Smith**",
        usage_html: "(autocompletes from @_joe)",
        output_html: '
Joe Smith
',
        effect_html: "(links to profile but doesn't notify Joe Smith)",
    },
    {
        markdown: "@**all**",
        effect_html: "(notifies all recipients)",
    },
    {
        markdown: "#**streamName**",
        output_html: "
#streamName
",
        effect_html: "(links to a stream)",
    },
    {
        markdown: "/me is busy working",
        output_html: '
Iago is busy working
',
        usage_html: "(send a status message as user Iago)",
    },
    {
        markdown: "Some inline `code`",
    },
    {
        markdown: `\
\`\`\`
def zulip():
    print "Zulip"
\`\`\``,
    },
    {
        markdown: `\
\`\`\`python
def zulip():
    print "Zulip"
\`\`\``,
        output_html: `\

def zulip():
    print "Zulip"

`,
    },
    {
        note_html: $t_html(
            {
                defaultMessage:
                    "To add syntax highlighting to a multi-line code block, add the language's first <z-link>Pygments short name</z-link> after the first set of back-ticks. You can also make a code block by indenting each line with 4 spaces.",
            },
            {
                "z-link": (content_html) =>
                    `<a target="_blank" rel="noopener noreferrer" href="https://pygments.org/docs/lexers/">${content_html}</a>`,
            },
        ),
    },
    {
        markdown: "> Quoted",
    },
    {
        markdown: `\
\`\`\`quote
Quoted block
\`\`\``,
    },
    {
        markdown: `\
\`\`\`spoiler Always visible heading
This text won't be visible until the user clicks.
\`\`\``,
    },
    {
        markdown: "Some inline math $$ e^{i \\pi} + 1 = 0 $$",
    },
    {
        markdown: `\
\`\`\`math
\\int_{0}^{1} f(x) dx
\`\`\``,
    },
    {
        note_html: $t_html(
            {
                defaultMessage:
                    "You can also make <z-link>tables</z-link> with this <z-link>Markdown-ish table syntax</z-link>.",
            },
            {
                "z-link": (content_html) =>
                    `<a target="_blank" rel="noopener noreferrer" href="https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#wiki-tables">${content_html}</a>`,
            },
        ),
    },
];

export function set_up_toggler() {
    for (const row of markdown_help_rows) {
        if (row.markdown && !row.output_html) {
            const message = {raw_content: row.markdown};
            markdown.apply_markdown(message);
            row.output_html = util.clean_user_content_links(message.content);
        }
    }

    const $markdown_help = $(render_markdown_help({markdown_help_rows}));
    $markdown_help.find(".rendered_markdown").each(function () {
        rendered_markdown.update_elements($(this));
    });
    $(".informational-overlays .overlay-body").append($markdown_help);

    const opts = {
        selected: 0,
        child_wants_focus: true,
        values: [
            {label: $t({defaultMessage: "Keyboard shortcuts"}), key: "keyboard-shortcuts"},
            {label: $t({defaultMessage: "Message formatting"}), key: "message-formatting"},
            {label: $t({defaultMessage: "Search operators"}), key: "search-operators"},
        ],
        callback(name, key) {
            $(".overlay-modal").hide();
            $(`#${CSS.escape(key)}`).show();
            ui.get_scroll_element($(`#${CSS.escape(key)}`).find(".modal-body")).trigger("focus");
        },
    };

    toggler = components.toggle(opts);
    const elem = toggler.get();
    elem.addClass("large allow-overflow");

    const modals = opts.values.map((item) => {
        const key = item.key; // e.g. message-formatting
        const modal = $(`#${CSS.escape(key)}`).find(".modal-body");
        return modal;
    });

    for (const modal of modals) {
        ui.get_scroll_element(modal).prop("tabindex", 0);
        keydown_util.handle({
            elem: modal,
            handlers: {
                ArrowLeft: toggler.maybe_go_left,
                ArrowRight: toggler.maybe_go_right,
            },
        });
    }

    $(".informational-overlays .overlay-tabs").append(elem);

    common.adjust_mac_shortcuts(".hotkeys_table .hotkey kbd");
    common.adjust_mac_shortcuts("#markdown-instructions kbd");
}

export function show(target) {
    if (!toggler) {
        set_up_toggler();
    }

    const overlay = $(".informational-overlays");

    if (!overlay.hasClass("show")) {
        overlays.open_overlay({
            name: "informationalOverlays",
            overlay,
            on_close() {
                browser_history.exit_overlay();
            },
        });
    }

    if (target) {
        toggler.goto(target);
    }
}
<|endoftext|>


<commit_before>// General purpose plugin for creating menu windows
var Menu = function(options)
{
    this.title = options.title || 'Menu';
    this.selector = options.selector || false;
    this.class = options.class;
    this.buttons = options.buttons;
    this.state = options.state;

    // Initialize the menu
    this.init();
    this.events();
}

Menu.prototype.init = function()
{
    // Clone the menu template
    this.template = $('.templates .menu').clone();
    $(this.template).find('.title .text').text(this.title);

    if(this.class)
    {
        $(this.template).addClass(this.class);
    }

    if(this.selector)
    {
        $(this.template).find('.content').el[0].appendChild($(this.selector).el[0]);
    }

    if(this.buttons)
    {
        $(this.template).find('.title .button').style({display: 'none'});

        for(var i = 0, l = this.buttons.length; i < l; i++)
        {
            var button = this.buttons[i];
            $(this.template).find('.title .' + button).style({display: 'block'});
        }
    }

    // Restore this menu to its original size / position from local storage
    var size = localStorage.getItem(this.title + '-size');
    var position = localStorage.getItem(this.title + '-pos');
    var state = this.state || localStorage.getItem(this.title + '-state');

    if(size)
    {
        size = JSON.parse(size);
        $(this.template).find('.content').style({height: size.height + 'px', width: size.width + 'px'});
    }

    if(position)
    {
        position = JSON.parse(position);
        $(this.template).style({top: position.top + 'px', left: position.left + 'px'});
    }

    $('.viewport').el[0].appendChild(this.template);

    // Create a minimized template for use latter
    this.minimized = $('.templates .minimized').clone();
    $(this.minimized).find('.title').text(this.title);

    // Check if the menu should start minimized or closed
    if(state == 'minimized')
    {
        this.minimize();
    }
    else if(state == 'closed')
    {
        this.close();
    }
}

// Bind specific events for this menu
Menu.prototype.events = function()
{
    var menu = this;

    $(menu.template).on('click', '.minimize', function()
    {
        menu.minimize();
    });

    $(menu.template).on('click', '.close', function()
    {
        menu.close();
    });

    $(menu.minimized).on('click', function()
    {
        menu.restore();
    });

    // Allow other events to trigger menu menu
    $(menu.template).on('minimize', function()
    {
        menu.minimize();
    });

    $(menu.template).on('close', function()
    {
        menu.close();
    });

    $(menu.template).on('restore', function()
    {
        menu.restore();
    });

    // Allow dragging the menu by the title bar
    $(menu.template).dragondrop({handle: '.title'});

    $(menu.template).on('dragend', function()
    {
        menu.save();
    });

    var resize = $(menu.template).find('.resize');
    resize.dragondrop({position: 'static'});

    resize.on('dragmove', function(event)
    {
        var delta = event.detail.delta;
        menu.resize(delta);

        resize.trigger('dragreset');
    });

    resize.on('dragend', function(event)
    {
        menu.save();
        $(menu.template).trigger('resized');
    });
}

// Minimize this menu to the bottom of the screen
Menu.prototype.minimize = function()
{
    $(this.template).style({display: 'none'});
    $('.tray').el[0].appendChild(this.minimized);
    localStorage.setItem(this.title + '-state', 'minimized');
}

// Restore a minimized menu to its original position
Menu.prototype.restore = function()
{
    $(this.template).style({display: 'block'});

    if(document.contains(this.minimized))
    {
        $(this.minimized).remove();
    }

    localStorage.setItem(this.title + '-state', 'active');
}

// Resize a menu
Menu.prototype.resize = function(delta)
{
    // Get the current size
    var size = $(this.template).find('.content').size();

    // Enforce a minimum size of 120x120 pixels
    if(size.width + delta.x < 120)
    {
        size.width = '120px';
    }
    else
    {
        size.width = size.width + delta.x + 'px';
    }

    if(size.height + delta.y < 120)
    {
        size.height = '120px';
    }
    else
    {
        size.height = size.height + delta.y + 'px'
    }

    // Resize this menu
    $(this.template).find('.content').style(size);
}

// Save the position / state of the menu in local storage
Menu.prototype.save = function()
{
    var size = $(this.template).find('.content').size();
    var position = $(this.template).position();

    localStorage.setItem(this.title + '-size', JSON.stringify(size))
    localStorage.setItem(this.title + '-pos', JSON.stringify(position));
}

// Close a menu
Menu.prototype.close = function()
{
    $(this.template).style({display: 'none'});
    localStorage.setItem(this.title + '-state', 'closed');
}

module.exports = Menu;
<commit_msg>Fixed position initialization for minimized menus<commit_after>// General purpose plugin for creating menu windows
var Menu = function(options)
{
    this.title = options.title || 'Menu';
    this.selector = options.selector || false;
    this.class = options.class;
    this.buttons = options.buttons;
    this.state = options.state;

    // Initialize the menu
    this.init();
    this.events();
}

Menu.prototype.init = function()
{
    // Clone the menu template
    this.template = $('.templates .menu').clone();
    $(this.template).find('.title .text').text(this.title);

    if(this.class)
    {
        $(this.template).addClass(this.class);
    }

    if(this.selector)
    {
        $(this.template).find('.content').el[0].appendChild($(this.selector).el[0]);
    }

    if(this.buttons)
    {
        $(this.template).find('.title .button').style({display: 'none'});

        for(var i = 0, l = this.buttons.length; i < l; i++)
        {
            var button = this.buttons[i];
            $(this.template).find('.title .' + button).style({display: 'block'});
        }
    }

    // Restore this menu to its original size / position from local storage
    var size = localStorage.getItem(this.title + '-size');
    var position = localStorage.getItem(this.title + '-pos');
    var state = this.state || localStorage.getItem(this.title + '-state');

    if(size)
    {
        size = JSON.parse(size);
        $(this.template).find('.content').style({height: size.height + 'px', width: size.width + 'px'});
    }

    if(position)
    {
        position = JSON.parse(position);
        $(this.template).style({top: position.top + 'px', left: position.left + 'px'});
    }

    $('.viewport').el[0].appendChild(this.template);

    // Create a minimized template for use latter
    this.minimized = $('.templates .minimized').clone();
    $(this.minimized).find('.title').text(this.title);

    // Horrible hack because minimizing / closing before dragondrop initializes resets the menu position
    var menu = this;

    setTimeout(function()
    {
        // Check if the menu should start minimized or closed
        if(state == 'minimized')
        {
            menu.minimize();
        }
        else if(state == 'closed')
        {
            menu.close();
        }
    }, 1);
}

// Bind specific events for this menu
Menu.prototype.events = function()
{
    var menu = this;

    $(menu.template).on('click', '.minimize', function()
    {
        menu.minimize();
    });

    $(menu.template).on('click', '.close', function()
    {
        menu.close();
    });

    $(menu.minimized).on('click', function()
    {
        menu.restore();
    });

    // Allow other events to trigger menu menu
    $(menu.template).on('minimize', function()
    {
        menu.minimize();
    });

    $(menu.template).on('close', function()
    {
        menu.close();
    });

    $(menu.template).on('restore', function()
    {
        menu.restore();
    });

    // Allow dragging the menu by the title bar
    $(menu.template).dragondrop({handle: '.title'});

    $(menu.template).on('dragend', function()
    {
        menu.save();
    });

    var resize = $(menu.template).find('.resize');
    resize.dragondrop({position: 'static'});

    resize.on('dragmove', function(event)
    {
        var delta = event.detail.delta;
        menu.resize(delta);

        resize.trigger('dragreset');
    });

    resize.on('dragend', function(event)
    {
        menu.save();
        $(menu.template).trigger('resized');
    });
}

// Minimize this menu to the bottom of the screen
Menu.prototype.minimize = function()
{
    $(this.template).style({display: 'none'});
    $('.tray').el[0].appendChild(this.minimized);
    localStorage.setItem(this.title + '-state', 'minimized');
}

// Restore a minimized menu to its original position
Menu.prototype.restore = function()
{
    $(this.template).style({display: 'block'});

    if(document.contains(this.minimized))
    {
        $(this.minimized).remove();
    }

    localStorage.setItem(this.title + '-state', 'active');
}

// Resize a menu
Menu.prototype.resize = function(delta)
{
    // Get the current size
    var size = $(this.template).find('.content').size();

    // Enforce a minimum size of 120x120 pixels
    if(size.width + delta.x < 120)
    {
        size.width = '120px';
    }
    else
    {
        size.width = size.width + delta.x + 'px';
    }

    if(size.height + delta.y < 120)
    {
        size.height = '120px';
    }
    else
    {
        size.height = size.height + delta.y + 'px'
    }

    // Resize this menu
    $(this.template).find('.content').style(size);
}

// Save the position / state of the menu in local storage
Menu.prototype.save = function()
{
    var size = $(this.template).find('.content').size();
    var position = $(this.template).position();

    localStorage.setItem(this.title + '-size', JSON.stringify(size))
    localStorage.setItem(this.title + '-pos', JSON.stringify(position));
}

// Close a menu
Menu.prototype.close = function()
{
    $(this.template).style({display: 'none'});
    localStorage.setItem(this.title + '-state', 'closed');
}

module.exports = Menu;
<|endoftext|>


<commit_before>define(['js/core/EventDispatcher', 'url', 'querystring', 'underscore', 'flow', 'srv/core/Identity', 'js/core/Base'],
    function (EventDispatcher, Url, QueryString, _, flow, Identity, Base) {

        var undefined,
            Context = EventDispatcher.inherit('srv.core.Context', {

                $hooks: ["beginRequest", "beforeHeadersSend", "endRequest"],

                ctor: function (server, endPoint, request, response) {

                    this.$processingHooks = {};

                    this.server = server;
                    this.session = new server.$serverSessionFactory();
                    this.identity = new Identity(this, server);

                    this.endPoint = endPoint;
                    this.request = request;
                    this.response = response;

                    this._registerFilterHooks(server.$filters);

                    this._subClassResponse(response);

                    this._parseUrl(request, endPoint);
                    this._parsePostData(request);

                    this._extractCookies(request);

                    response.cookies = new Context.CookieManager(this);

                },

                /***
                 *
                 * @param name
                 * @param {Function} hookFunction
                 */
                addProcessingHook: function (name, hookFunction) {
                    var processingHookStorage = this.$processingHooks[name] || (this.$processingHooks[name] = []);
                    processingHookStorage.push(hookFunction);
                },

                _executeHook: function (name, callback) {
                    var context = this;

                    flow()
                        .seqEach(this.$processingHooks[name], function (hookFunction, cb) {
                            hookFunction(context, cb);
                        })
                        .exec(callback);
                },

                _registerFilterHooks: function (filters) {
                    // register filter hooks
                    for (var i = 0; i < this.$hooks.length; i++) {
                        var hookName = this.$hooks[i];
                        this.addProcessingHook(hookName, filters[hookName].bind(filters));
                    }
                },

                _subClassResponse: function (response) {

                    response.__end = response.end;
                    response.__writeHead = response.writeHead;
                    response.__write = response.write;

                    response.$context = this;

                    if (!response.__proto__.getHeaders) {
                        response.__proto__.getHeaders = function () {
                            return this._renderHeaders();
                        };
                    }

                    response.writeHead = Context.Response._writeHead;

                    response.write = Context.Response._write;

                    response.end = Context.Response._end;
                },

                _parseUrl: function (request, endpoint) {

                    var urlInfo = Url.parse(request.url);
                    request.urlInfo = urlInfo;
                    urlInfo.parameter = QueryString.parse(urlInfo.query);
                    request.get = urlInfo;

                    var host = request.headers["host"];
                    var baseUri = endpoint.protocol + "://" + host;

                    request.urlInfo.baseUri = baseUri;
                    request.urlInfo.uri = baseUri + request.urlInfo.pathname;

                },

                _parsePostData: function (request) {

                    if (request.method === "POST") {
                        try {
                            request.post = QueryString.parse(request.body.content);
                        } catch (e) {
                            this.log("Couldn't parse post parameters", "info");
                        }
                    }

                    if (!request.post) {
                        request.post = {};
                    }

                },

                _extractCookies: function (request) {

                    var cookies = request.headers["cookie"];
                    request.cookie = {};

                    if (!cookies) {
                        return;
                    }

                    cookies.split(";").forEach(function (cookie) {
                        var parts = cookie.split('=');
                        request.cookie[parts[0].trim()] = (parts[1] || "").trim();
                    });

                }

            });

        Context.Response = {

            _write: function (chunk, encoding) {
                var self = this;
                Context.Response._writeHeadHook.call(this, function () {
                    self.__write.call(self, chunk, encoding);
                });
            },

            _end: function () {
                if (this.$end) {
                    return false;
                }

                this.$end = true;

                var self = this;
                this.$context._executeHook("endRequest", function () {
                    self.__end.call(self);
                });
            },

            _writeHead: function (statusCode, reasonPhrase, headers) {
                if (this.$headersSent) {
                    throw new Error("Headers already sent.");
                }

                if (typeof arguments[1] == 'string') {
                    this.$reasonPhrase = arguments[1];
                } else {
                    headers = reasonPhrase;
                }

                if (headers) {
                    for (var key in headers) {
                        if (headers.hasOwnProperty(key)) {
                            this.setHeader(key, headers[key]);
                        }
                    }
                }

                this.statusCode = statusCode;
                Context.Response._writeHeadHook.call(this);
            },

            _writeHeadHook: function (callback) {
                // internal write head logic

                var self = this;

                if (!this.$headersSent) {
                    if (this.$writeHeadCallbacks) {
                        // head write in process -> queue callback
                        this.$writeHeadCallbacks.push(callback);
                    } else {
                        this.$writeHeadCallbacks = [callback];

                        flow()
                            .seq(function (cb) {
                                self.$context._executeHook("beforeHeadersSend", cb);
                            })
                            .exec(function () {
                                // TODO: how to handle errors here ?
                                self.__writeHead.call(self, self.statusCode, self.$reasonPhrase);
                                self.$headersSent = true;

                                for (var i = 0; i < self.$writeHeadCallbacks.length; i++) {
                                    var writeHeadCallback = self.$writeHeadCallbacks[i];
                                    writeHeadCallback && writeHeadCallback();
                                }
                            });
                    }
                } else {
                    callback();
                }
            }

        };

        Context.CookieManager = Base.inherit('srv.core.Context.CookieManager', {

            ctor: function (context) {
                this.cookie = {};
                var self = this;
                context.addProcessingHook("beforeHeadersSend", function (context, callback) {
                    self._writeCookiesToHead(context, callback);
                });
            },

            set: function (name, value, options) {
                this.cookie[name] = new Context.CookieManager.Cookie(name, value, options)
            },

            remove: function (name) {
                this.set(name);
            },

            _writeCookiesToHead: function (context, callback) {

                var headers = [];

                for (var key in this.cookie) {
                    if (this.cookie.hasOwnProperty(key)) {
                        headers.push(this.cookie[key].toHeader())
                    }
                }

                context.response.setHeader("Set-Cookie", headers);
                callback();
            }
        });

        Context.CookieManager.Cookie = Base.inherit('srv.core.Context.CookieManager.Cookie', {

            ctor: function (name, value, options) {

                options = options || {};
                _.defaults(options, {
                    path: "/",
                    expires: undefined,
                    domain: undefined,
                    httpOnly: true,
                    secure: false,

                    value: value,
                    name: name
                });

                this.$ = options;

            },

            toString: function () {
                return this.$.name + "=" + this.$.value
            },

            toHeader: function () {
                var header = this.toString();

                if (this.$.path) {
                    header += "; path=" + this.$.path
                }

                if (this.$.value === undefined) {
                    // undefined value -> remove cookie
                    this.$.expires = new Date(0);
                }

                if (this.$.expires) {
                    header += "; expires=" + this.$.expires.toUTCString();
                }

                if (this.$.domain) {
                    header += "; domain=" + this.$.domain;
                }

                if (this.$.secure) {
                    header += "; secure";
                }

                if (this.httpOnly) {
                    header += "; httponly";
                }

                return header
            }

        });

        return Context;
    });<commit_msg>made _writeHead more stable in Context<commit_after>define(['js/core/EventDispatcher', 'url', 'querystring', 'underscore', 'flow', 'srv/core/Identity', 'js/core/Base'],
    function (EventDispatcher, Url, QueryString, _, flow, Identity, Base) {

        var undefined,
            Context = EventDispatcher.inherit('srv.core.Context', {

                $hooks: ["beginRequest", "beforeHeadersSend", "endRequest"],

                ctor: function (server, endPoint, request, response) {

                    this.$processingHooks = {};

                    this.server = server;
                    this.session = new server.$serverSessionFactory();
                    this.identity = new Identity(this, server);

                    this.endPoint = endPoint;
                    this.request = request;
                    this.response = response;

                    this._registerFilterHooks(server.$filters);

                    this._subClassResponse(response);

                    this._parseUrl(request, endPoint);
                    this._parsePostData(request);

                    this._extractCookies(request);

                    response.cookies = new Context.CookieManager(this);

                },

                /***
                 *
                 * @param name
                 * @param {Function} hookFunction
                 */
                addProcessingHook: function (name, hookFunction) {
                    var processingHookStorage = this.$processingHooks[name] || (this.$processingHooks[name] = []);
                    processingHookStorage.push(hookFunction);
                },

                _executeHook: function (name, callback) {
                    var context = this;

                    flow()
                        .seqEach(this.$processingHooks[name], function (hookFunction, cb) {
                            hookFunction(context, cb);
                        })
                        .exec(callback);
                },

                _registerFilterHooks: function (filters) {
                    // register filter hooks
                    for (var i = 0; i < this.$hooks.length; i++) {
                        var hookName = this.$hooks[i];
                        this.addProcessingHook(hookName, filters[hookName].bind(filters));
                    }
                },

                _subClassResponse: function (response) {

                    response.__end = response.end;
                    response.__writeHead = response.writeHead;
                    response.__write = response.write;

                    response.$context = this;

                    if (!response.__proto__.getHeaders) {
                        response.__proto__.getHeaders = function () {
                            return this._renderHeaders();
                        };
                    }

                    response.writeHead = Context.Response._writeHead;

                    response.write = Context.Response._write;

                    response.end = Context.Response._end;
                },

                _parseUrl: function (request, endpoint) {

                    var urlInfo = Url.parse(request.url);
                    request.urlInfo = urlInfo;
                    urlInfo.parameter = QueryString.parse(urlInfo.query);
                    request.get = urlInfo;

                    var host = request.headers["host"];
                    var baseUri = endpoint.protocol + "://" + host;

                    request.urlInfo.baseUri = baseUri;
                    request.urlInfo.uri = baseUri + request.urlInfo.pathname;

                },

                _parsePostData: function (request) {

                    if (request.method === "POST") {
                        try {
                            request.post = QueryString.parse(request.body.content);
                        } catch (e) {
                            this.log("Couldn't parse post parameters", "info");
                        }
                    }

                    if (!request.post) {
                        request.post = {};
                    }

                },

                _extractCookies: function (request) {

                    var cookies = request.headers["cookie"];
                    request.cookie = {};

                    if (!cookies) {
                        return;
                    }

                    cookies.split(";").forEach(function (cookie) {
                        var parts = cookie.split('=');
                        request.cookie[parts[0].trim()] = (parts[1] || "").trim();
                    });

                }

            });

        Context.Response = {

            _write: function (chunk, encoding) {
                var self = this;
                Context.Response._writeHeadHook.call(this, function () {
                    self.__write.call(self, chunk, encoding);
                });
            },

            _end: function () {
                if (this.$end) {
                    return false;
                }

                this.$end = true;

                var self = this;
                this.$context._executeHook("endRequest", function () {
                    self.__end.call(self);
                });
            },

            _writeHead: function (statusCode, reasonPhrase, headers) {
                if (this.$headersSent) {
                    throw new Error("Headers already sent.");
                }

                var args = Array.prototype.slice.call(arguments);

                if (args.length === 3) {
                    this.$reasonPhrase = arguments[1];
                } else {
                    headers = reasonPhrase;
                }

                if (headers) {
                    for (var key in headers) {
                        if (headers.hasOwnProperty(key)) {
                            this.setHeader(key, headers[key]);
                        }
                    }
                }

                this.statusCode = statusCode;
                Context.Response._writeHeadHook.call(this);
            },

            _writeHeadHook: function (callback) {
                // internal write head logic

                var self = this;

                if (!this.$headersSent) {
                    if (this.$writeHeadCallbacks) {
                        // head write in process -> queue callback
                        this.$writeHeadCallbacks.push(callback);
                    } else {
                        this.$writeHeadCallbacks = [callback];

                        flow()
                            .seq(function (cb) {
                                self.$context._executeHook("beforeHeadersSend", cb);
                            })
                            .exec(function () {
                                // TODO: how to handle errors here ?
                                self.__writeHead.call(self, self.statusCode, self.$reasonPhrase);
                                self.$headersSent = true;

                                for (var i = 0; i < self.$writeHeadCallbacks.length; i++) {
                                    var writeHeadCallback = self.$writeHeadCallbacks[i];
                                    writeHeadCallback && writeHeadCallback();
                                }
                            });
                    }
                } else {
                    callback();
                }
            }

        };

        Context.CookieManager = Base.inherit('srv.core.Context.CookieManager', {

            ctor: function (context) {
                this.cookie = {};
                var self = this;
                context.addProcessingHook("beforeHeadersSend", function (context, callback) {
                    self._writeCookiesToHead(context, callback);
                });
            },

            set: function (name, value, options) {
                this.cookie[name] = new Context.CookieManager.Cookie(name, value, options)
            },

            remove: function (name) {
                this.set(name);
            },

            _writeCookiesToHead: function (context, callback) {

                var headers = [];

                for (var key in this.cookie) {
                    if (this.cookie.hasOwnProperty(key)) {
                        headers.push(this.cookie[key].toHeader())
                    }
                }

                context.response.setHeader("Set-Cookie", headers);
                callback();
            }
        });

        Context.CookieManager.Cookie = Base.inherit('srv.core.Context.CookieManager.Cookie', {

            ctor: function (name, value, options) {

                options = options || {};
                _.defaults(options, {
                    path: "/",
                    expires: undefined,
                    domain: undefined,
                    httpOnly: true,
                    secure: false,

                    value: value,
                    name: name
                });

                this.$ = options;

            },

            toString: function () {
                return this.$.name + "=" + this.$.value
            },

            toHeader: function () {
                var header = this.toString();

                if (this.$.path) {
                    header += "; path=" + this.$.path
                }

                if (this.$.value === undefined) {
                    // undefined value -> remove cookie
                    this.$.expires = new Date(0);
                }

                if (this.$.expires) {
                    header += "; expires=" + this.$.expires.toUTCString();
                }

                if (this.$.domain) {
                    header += "; domain=" + this.$.domain;
                }

                if (this.$.secure) {
                    header += "; secure";
                }

                if (this.httpOnly) {
                    header += "; httponly";
                }

                return header
            }

        });

        return Context;
    });<|endoftext|>