<commit_before>/**
 * Created by ksinger on 22.01.2016.
 */

import { createSelector } from 'reselect';
import Immutable from 'immutable';
import won from './won-es6';
import {
    decodeUriComponentProperly,
    msStringToDate,
    is,
} from './utils';

import {
    selectTimestamp,
} from './won-utils';

import { relativeTime } from './won-label-utils';

export const selectConnections = state => state.getIn(['connections']);
export const selectEvents = state => state.getIn(['events', 'events']);
export const selectOwnNeeds = state => state.getIn(['needs', 'ownNeeds']);
export const selectTheirNeeds = state => state.getIn(['needs', 'theirNeeds']);
export const selectLastUpdateTime = state => state.get('lastUpdateTime');
export const selectRouterParams = state => state.getIn(['router', 'currentParams']);
export const selectDrafts = state => state.get('drafts');

export const selectUnreadEventUris = state => state
    .getIn(['events', 'unreadEventUris']);

//TODO the earlier unreadEvents was organised by need-uri!

export const selectRemoteEvents = createSelector(
    selectEvents,
    events => {
        const remoteUrisAndEvents = events
            .toList()
            .map(e => {
                let remote = e.get('hasCorrespondingRemoteMessage') // select remote
                if(is('String', remote)) remote = events.get(remote); // for those rare cases where remote is only a uri
                if(!remote) return undefined;
                remote = remote.set('correspondsToOwnMsg', e); //add back-reference to it
                return remote && [remote.get('uri'), remote]
            })
            .filter(uriAndEvent => uriAndEvent); // filter out `undefined`s
        return Immutable.Map(remoteUrisAndEvents)
    }
)

export const selectUnreadEvents = createSelector(
    selectEvents,
    selectUnreadEventUris,
    (events, unreadEventUris) =>
        unreadEventUris.map(eventUri => events.get(eventUri))
);

//const selectUnreadEvents = state => state.getIn(['events', 'unreadEventUris']);

/**
 * @param {object} state
 * @return {object} events grouped by need.
 *      `unreadEventsByNeed.get(needUri)`, e.g.:
 *      `unreadEventsByNeed.get('http://example.org/won/resource/need/1234')`
 */
export const selectUnreadEventsByNeed = createSelector(
    selectUnreadEvents, selectConnections,
    // group by need, resulting in:  `{ <needUri>: { <cnctUri>: e1, <cnctUri>: e2, ...}, <needUri>: ...}`
    //TODO hasReceiverNeed is not guaranteed to exist.
    (unreadEvents, connections) => unreadEvents.groupBy(e => {
        const connectionUri = e.get('hasReceiver');
        return connections.getIn([connectionUri, 'belongsToNeed']);
    })
);

/**
 * from: state.events.unreadEventUris  of "type" ~Map<connection,latestevent>
 * to: ~Map<receiverneeduri, Map<connection,latestevent>>, e.g.:
 *     { <needUri>: { <eventType> : { <cnctUri>: e1, <cnctUri>: e2, ...}, <eventType> :... }, <needUri>: ...}
 *
 * access events as `const event = groupedEvents.getIn([needUri, eventType, cnctUri])`
 *
 * @param {object} state
 * @return {object} events grouped primarily by need and secondarily by type
 */
export const selectUnreadEventsByNeedAndType = createSelector(
    selectUnreadEventsByNeed,
    eventsGroupedByNeed =>
        // group by event-type
        eventsGroupedByNeed.map(groupByType)
);

function groupByType(events) {
    return events.groupBy(e =>
        e.get('hasMessageType') ||
        e.getIn(['hasCorrespondingRemoteMessage', 'hasMessageType'])
    )
}

/**
 * @param {object} state
 * @return {object} event counts for each need. access via
 *      `unreadCounts.getIn([needUri, eventType])`, e.g.:
 *      `unreadCounts.getIn(['http://example.org/won/resource/need/1234', won.EVENT.HINT_RECEIVED])`
 */
export const selectUnreadCountsByNeedAndType = createSelector(
    selectUnreadEventsByNeedAndType,
    unreadEventsByNeedAndType =>
        unreadEventsByNeedAndType.map(eventsByType => //looking at single need's events grouped by type
            eventsByType.map(evnts => evnts.size) // looking at specific need and type -> just count now
        )

);

/**
 * @param {object} state
 * @return {object} event counts for each event type. access via
 *      `unreadCountsByType.get(eventType)`, e.g.:
 *      `unreadCountsByType.getIn(won.EVENT.HINT_RECEIVED)`
 */
export const selectUnreadCountsByType = createSelector(
    selectUnreadEvents,
    unreadEvents => groupByType(unreadEvents)
        .map(eventsOfType => eventsOfType.size)
)

/**
 * selects a map of `connectionUri -> { connection, events, ownNeed, remoteNeed }`
 * - thus: everything a connection has direct references to. Use this selector
 * when you're needing connection-centric data (e.g. for a view with a strong
 * focus on the connection)
 *
 * NOTE: the app-state used to have events and needs stored in this fashion.
 * Thus, this selector is also used to allow older code to use the new
 * state-structure with minimal changes.
 */
export const selectAllByConnections = createSelector(
    state => state, //reselect's createSelector always needs a dependency
    state => state
        .getIn(['connections'])
        .map(connection => allByConnection(connection)(state))
);
const allByConnection = (connection) => (state) => {
    const ownNeedUri = connection.get('belongsToNeed');
    const ownNeed = state.getIn(['needs', 'ownNeeds', ownNeedUri]);

    const remoteNeedUri = connection.get('hasRemoteNeed');
    const remoteNeed = state.getIn(['needs', 'theirNeeds', remoteNeedUri]);

    const events = connection
        .get('hasEvents')
        .map(eventUri => state.getIn(['events', 'events', eventUri]))
        .filter(event => !!event);

    return Immutable.Map({ connection, events, ownNeed, remoteNeed });
};
const allByConnectionUri = (connectionUri)  => {
    const connection = state.getIn(['connections', connectionUri]);
    return allByConnection(connection);
};

//TODO there's certainly more elegant ways to implement this selector than first grouping by connection then by need
export const selectConnectionsByNeed = createSelector(
    selectAllByConnections,
        connections => connections
        .map(cnct => Immutable.fromJS(cnct)) //TODO this is a workaround. atm connections aren't ImmutableJS-objects
        .groupBy(cnct => cnct.getIn(['ownNeed', '@id']))
);

export const selectOpenDraft = createSelector(
    selectRouterParams, selectDrafts,
    (routerParams, drafts) =>
        drafts.get(routerParams.get('draftId'))
);

export const selectOpenConnectionUri = createSelector(
    selectRouterParams,
    selectConnections,
    (routerParams, connections) => {
        //de-escaping is lost in transpiling if not done in two steps :|
        const openConnectionUri = decodeUriComponentProperly(
            routerParams.get('connectionUri') ||
            routerParams.get('openConversation')
        );

        const myUri = decodeUriComponentProperly(routerParams.get('myUri')); //TODO deprecated parameter

        const theirUri = decodeUriComponentProperly(routerParams.get('theirUri')); //TODO deprecated parameter

        if(openConnectionUri) {
            return openConnectionUri;
        } else if (myUri && theirUri) {
            /*
             returns undefined when there's no
             connection like that in the state.
             */
            return connections
                .filter(c =>
                    c.get('belongsToNeed') === myUri  &&
                    c.get('hasRemoteNeed') === theirUri
                ).keySeq().first()
        } else {
            return undefined;
        }
    }
);

export const selectOpenConnection = createSelector(
    selectOpenConnectionUri, selectConnections,
    (uri, connections) =>
        connections.get(uri)
);

export const selectEventsOfOpenConnection = createSelector(
    selectOpenConnection, selectEvents,
    (connection, allEvents) => connection && connection
        .get('hasEvents')
        .map(eventUri => allEvents.get(eventUri))
);

export const selectConnectMessageOfOpenConnection = createSelector(
    selectEventsOfOpenConnection,
    events => events && events
        .filter(event =>
            event && (
                event.getIn(['hasCorrespondingRemoteMessage', 'hasMessageType']) === won.WONMSG.connectMessage ||
                event.get('hasMessageType') === won.WONMSG.connectMessage
            )
        )
        .first()
)

export const selectRequestTimestampOfOpenConnection = createSelector(
    selectConnectMessageOfOpenConnection,
    connectMsg => {

        if(!connectMsg) return;

        let timestamp;
        if (connectMsg.get('type') === won.WONMSG.FromExternal) {
            timestamp = connectMsg.get('hasReceivedTimestamp');
        } else if (connectMsg.getIn(['hasCorrespondingRemoteMessage', 'type']) === won.WONMSG.FromExternal) {
            timestamp = connectMsg.getIn(['hasCorrespondingRemoteMessage', 'hasReceivedTimestamp'])
        } else {
            throw new Error("Encountered connect message of unexpected " +
                "format (neither the message nor it's counterpart were " +
                "`FromExternal`, thus a the one our own node created)." );
        }
        return msStringToDate(timestamp)
    }
);

export const selectOpenPostUri = createSelector(
    state => state,
    state => {
        const encodedPostUri =
            state.getIn(['router', 'currentParams', 'postUri']) ||
            state.getIn(['router', 'currentParams', 'myUri']); //deprecated parameter
        return decodeUriComponentProperly(encodedPostUri);
    }
);

export const selectOpenPost = createSelector(
    selectOpenPostUri, selectOwnNeeds, selectTheirNeeds, selectLastUpdateTime,
    (openPostUri, ownNeeds, theirNeeds, lastUpdateTime) => {
        let post = ownNeeds.get(openPostUri) || theirNeeds.get(openPostUri);
        if(post) {
            const timestamp = relativeTime(lastUpdateTime, post.get('dct:created'));
            post = post.set('friendlyTimestamp', timestamp);
        }
        return post;
    }
)
export const selectOwningOpenPost = createSelector(
    selectOpenPostUri, selectOwnNeeds,
    (openPostUri, ownNeeds) => !!ownNeeds.get(openPostUri)
)

export const displayingOverview = createSelector(
    selectOpenPostUri,
    postUri => !postUri //if there's a postUri, this is almost certainly a detail view
)

export const selectLastUpdatedPerConnection = createSelector(
    selectAllByConnections,
    allByConnections => allByConnections.map(connectionAndRelated =>
        connectionAndRelated.get('events')
        .map( event =>
            //selectTimestamp(event, connectionAndRelated.getIn(['connection','uri']) )
            selectTimestamp(event)
        )
        /*
         * don't use events without timestamp
         * NOTE if there's no events with timestamps
         * for the connection:
         * `Immutable.List([]).max() === undefined`
         */
        .filter(timestamp => timestamp)
        .map(timestamp => Number.parseInt(timestamp))
        .max()
    )
);

window.selectAllByConnections4dbg = selectAllByConnections;
window.allByConnection4db = allByConnection;
<commit_msg>Minor white-space change.<commit_after>/**
 * Created by ksinger on 22.01.2016.
 */

import { createSelector } from 'reselect';
import Immutable from 'immutable';
import won from './won-es6';
import {
    decodeUriComponentProperly,
    msStringToDate,
    is,
} from './utils';

import {
    selectTimestamp,
} from './won-utils';

import { relativeTime } from './won-label-utils';

export const selectConnections = state => state.getIn(['connections']);
export const selectEvents = state => state.getIn(['events', 'events']);
export const selectOwnNeeds = state => state.getIn(['needs', 'ownNeeds']);
export const selectTheirNeeds = state => state.getIn(['needs', 'theirNeeds']);
export const selectLastUpdateTime = state => state.get('lastUpdateTime');
export const selectRouterParams = state => state.getIn(['router', 'currentParams']);
export const selectDrafts = state => state.get('drafts');

export const selectUnreadEventUris = state => state
    .getIn(['events', 'unreadEventUris']);

//TODO the earlier unreadEvents was organised by need-uri!

export const selectRemoteEvents = createSelector(
    selectEvents,
    events => {
        const remoteUrisAndEvents = events
            .toList()
            .map(e => {
                let remote = e.get('hasCorrespondingRemoteMessage') // select remote
                if(is('String', remote)) remote = events.get(remote); // for those rare cases where remote is only a uri
                if(!remote) return undefined;
                remote = remote.set('correspondsToOwnMsg', e); //add back-reference to it
                return remote && [remote.get('uri'), remote]
            })
            .filter(uriAndEvent => uriAndEvent); // filter out `undefined`s
        return Immutable.Map(remoteUrisAndEvents)
    }
)

export const selectUnreadEvents = createSelector(
    selectEvents,
    selectUnreadEventUris,
    (events, unreadEventUris) =>
        unreadEventUris.map(eventUri => events.get(eventUri))
);

//const selectUnreadEvents = state => state.getIn(['events', 'unreadEventUris']);

/**
 * @param {object} state
 * @return {object} events grouped by need.
 *      `unreadEventsByNeed.get(needUri)`, e.g.:
 *      `unreadEventsByNeed.get('http://example.org/won/resource/need/1234')`
 */
export const selectUnreadEventsByNeed = createSelector(
    selectUnreadEvents, selectConnections,
    // group by need, resulting in:  `{ <needUri>: { <cnctUri>: e1, <cnctUri>: e2, ...}, <needUri>: ...}`
    //TODO hasReceiverNeed is not guaranteed to exist.
    (unreadEvents, connections) => unreadEvents.groupBy(e => {
        const connectionUri = e.get('hasReceiver');
        return connections.getIn([connectionUri, 'belongsToNeed']);
    })
);

/**
 * from: state.events.unreadEventUris  of "type" ~Map<connection,latestevent>
 * to: ~Map<receiverneeduri, Map<connection,latestevent>>, e.g.:
 *     { <needUri>: { <eventType> : { <cnctUri>: e1, <cnctUri>: e2, ...}, <eventType> :... }, <needUri>: ...}
 *
 * access events as `const event = groupedEvents.getIn([needUri, eventType, cnctUri])`
 *
 * @param {object} state
 * @return {object} events grouped primarily by need and secondarily by type
 */
export const selectUnreadEventsByNeedAndType = createSelector(
    selectUnreadEventsByNeed,
    eventsGroupedByNeed =>
        // group by event-type
        eventsGroupedByNeed.map(groupByType)
);

function groupByType(events) {
    return events.groupBy(e =>
        e.get('hasMessageType') ||
        e.getIn(['hasCorrespondingRemoteMessage', 'hasMessageType'])
    )
}

/**
 * @param {object} state
 * @return {object} event counts for each need. access via
 *      `unreadCounts.getIn([needUri, eventType])`, e.g.:
 *      `unreadCounts.getIn(['http://example.org/won/resource/need/1234', won.EVENT.HINT_RECEIVED])`
 */
export const selectUnreadCountsByNeedAndType = createSelector(
    selectUnreadEventsByNeedAndType,
    unreadEventsByNeedAndType =>
        unreadEventsByNeedAndType.map(eventsByType => //looking at single need's events grouped by type
            eventsByType.map(evnts => evnts.size) // looking at specific need and type -> just count now
        )

);

/**
 * @param {object} state
 * @return {object} event counts for each event type. access via
 *      `unreadCountsByType.get(eventType)`, e.g.:
 *      `unreadCountsByType.getIn(won.EVENT.HINT_RECEIVED)`
 */
export const selectUnreadCountsByType = createSelector(
    selectUnreadEvents,
    unreadEvents => groupByType(unreadEvents)
        .map(eventsOfType => eventsOfType.size)
);

/**
 * selects a map of `connectionUri -> { connection, events, ownNeed, remoteNeed }`
 * - thus: everything a connection has direct references to. Use this selector
 * when you're needing connection-centric data (e.g. for a view with a strong
 * focus on the connection)
 *
 * NOTE: the app-state used to have events and needs stored in this fashion.
 * Thus, this selector is also used to allow older code to use the new
 * state-structure with minimal changes.
 */
export const selectAllByConnections = createSelector(
    state => state, //reselect's createSelector always needs a dependency
    state => state
        .getIn(['connections'])
        .map(connection => allByConnection(connection)(state))
);
const allByConnection = (connection) => (state) => {
    const ownNeedUri = connection.get('belongsToNeed');
    const ownNeed = state.getIn(['needs', 'ownNeeds', ownNeedUri]);

    const remoteNeedUri = connection.get('hasRemoteNeed');
    const remoteNeed = state.getIn(['needs', 'theirNeeds', remoteNeedUri]);

    const events = connection
        .get('hasEvents')
        .map(eventUri => state.getIn(['events', 'events', eventUri]))
        .filter(event => !!event);

    return Immutable.Map({ connection, events, ownNeed, remoteNeed });
};
const allByConnectionUri = (connectionUri)  => {
    const connection = state.getIn(['connections', connectionUri]);
    return allByConnection(connection);
};

//TODO there's certainly more elegant ways to implement this selector than first grouping by connection then by need
export const selectConnectionsByNeed = createSelector(
    selectAllByConnections,
        connections => connections
        .map(cnct => Immutable.fromJS(cnct)) //TODO this is a workaround. atm connections aren't ImmutableJS-objects
        .groupBy(cnct => cnct.getIn(['ownNeed', '@id']))
);

export const selectOpenDraft = createSelector(
    selectRouterParams, selectDrafts,
    (routerParams, drafts) =>
        drafts.get(routerParams.get('draftId'))
);

export const selectOpenConnectionUri = createSelector(
    selectRouterParams,
    selectConnections,
    (routerParams, connections) => {
        //de-escaping is lost in transpiling if not done in two steps :|
        const openConnectionUri = decodeUriComponentProperly(
            routerParams.get('connectionUri') ||
            routerParams.get('openConversation')
        );

        const myUri = decodeUriComponentProperly(routerParams.get('myUri')); //TODO deprecated parameter

        const theirUri = decodeUriComponentProperly(routerParams.get('theirUri')); //TODO deprecated parameter

        if(openConnectionUri) {
            return openConnectionUri;
        } else if (myUri && theirUri) {
            /*
             returns undefined when there's no
             connection like that in the state.
             */
            return connections
                .filter(c =>
                    c.get('belongsToNeed') === myUri  &&
                    c.get('hasRemoteNeed') === theirUri
                ).keySeq().first()
        } else {
            return undefined;
        }
    }
);

export const selectOpenConnection = createSelector(
    selectOpenConnectionUri, selectConnections,
    (uri, connections) =>
        connections.get(uri)
);

export const selectEventsOfOpenConnection = createSelector(
    selectOpenConnection, selectEvents,
    (connection, allEvents) => connection && connection
        .get('hasEvents')
        .map(eventUri => allEvents.get(eventUri))
);

export const selectConnectMessageOfOpenConnection = createSelector(
    selectEventsOfOpenConnection,
    events => events && events
        .filter(event =>
            event && (
                event.getIn(['hasCorrespondingRemoteMessage', 'hasMessageType']) === won.WONMSG.connectMessage ||
                event.get('hasMessageType') === won.WONMSG.connectMessage
            )
        )
        .first()
)

export const selectRequestTimestampOfOpenConnection = createSelector(
    selectConnectMessageOfOpenConnection,
    connectMsg => {

        if(!connectMsg) return;

        let timestamp;
        if (connectMsg.get('type') === won.WONMSG.FromExternal) {
            timestamp = connectMsg.get('hasReceivedTimestamp');
        } else if (connectMsg.getIn(['hasCorrespondingRemoteMessage', 'type']) === won.WONMSG.FromExternal) {
            timestamp = connectMsg.getIn(['hasCorrespondingRemoteMessage', 'hasReceivedTimestamp'])
        } else {
            throw new Error("Encountered connect message of unexpected " +
                "format (neither the message nor it's counterpart were " +
                "`FromExternal`, thus a the one our own node created)." );
        }
        return msStringToDate(timestamp)
    }
);

export const selectOpenPostUri = createSelector(
    state => state,
    state => {
        const encodedPostUri =
            state.getIn(['router', 'currentParams', 'postUri']) ||
            state.getIn(['router', 'currentParams', 'myUri']); //deprecated parameter
        return decodeUriComponentProperly(encodedPostUri);
    }
);

export const selectOpenPost = createSelector(
    selectOpenPostUri, selectOwnNeeds, selectTheirNeeds, selectLastUpdateTime,
    (openPostUri, ownNeeds, theirNeeds, lastUpdateTime) => {
        let post = ownNeeds.get(openPostUri) || theirNeeds.get(openPostUri);
        if(post) {
            const timestamp = relativeTime(lastUpdateTime, post.get('dct:created'));
            post = post.set('friendlyTimestamp', timestamp);
        }
        return post;
    }
)
export const selectOwningOpenPost = createSelector(
    selectOpenPostUri, selectOwnNeeds,
    (openPostUri, ownNeeds) => !!ownNeeds.get(openPostUri)
)

export const displayingOverview = createSelector(
    selectOpenPostUri,
    postUri => !postUri //if there's a postUri, this is almost certainly a detail view
)

export const selectLastUpdatedPerConnection = createSelector(
    selectAllByConnections,
    allByConnections => allByConnections.map(connectionAndRelated =>
        connectionAndRelated.get('events')
        .map( event =>
            //selectTimestamp(event, connectionAndRelated.getIn(['connection','uri']) )
            selectTimestamp(event)
        )
        /*
         * don't use events without timestamp
         * NOTE if there's no events with timestamps
         * for the connection:
         * `Immutable.List([]).max() === undefined`
         */
        .filter(timestamp => timestamp)
        .map(timestamp => Number.parseInt(timestamp))
        .max()
    )
);

window.selectAllByConnections4dbg = selectAllByConnections;
window.allByConnection4db = allByConnection;
<|endoftext|>


<commit_before>/// <reference path="../../../../../argos-sdk/libraries/ext/ext-core-debug.js"/>
/// <reference path="../../../../../argos-sdk/libraries/sdata/sdata-client-debug"/>
/// <reference path="../../../../../argos-sdk/libraries/Simplate.js"/>
/// <reference path="../../../../../argos-sdk/src/View.js"/>
/// <reference path="../../../../../argos-sdk/src/List.js"/>

Ext.namespace("Mobile.SalesLogix.Activity");

(function() {
    Mobile.SalesLogix.Activity.List = Ext.extend(Sage.Platform.Mobile.List, {
        //Templates
        itemTemplate: new Simplate([
            '
',
            '

',
            '{%! $$.contentTemplate %}',
            '
'
        ]),
        activityTimeTemplate: new Simplate([
            '{% if ($.Timeless) { %}',
            'All-Day',
            '{% } else { %}',
            '{%: Mobile.SalesLogix.Format.date($.StartDate, "h:mm") %}',
            ' {%: Mobile.SalesLogix.Format.date($.StartDate, "tt") %},',
            '{% } %}'
        ]),
        contentTemplate: new Simplate([
            '
',
            '{%= $$.activityTimeTemplate.apply($) %}',
            ' {%: $.Description %}',
            '
',
            '
{%: Mobile.SalesLogix.Format.date($.StartDate, "ddd M/d/yy", Sage.Platform.Mobile.Convert.toBoolean($.Timeless)) %} - {%= $$.nameTemplate.apply($) %}
'
        ]),
        nameTemplate: new Simplate([
            '{% if ($.ContactName) { %}',
            '{%: $.ContactName %} / {%: $.AccountName %}',
            '{% } else if ($.AccountName) { %}',
            '{%: $.AccountName %}',
            '{% } else { %}',
            '{%: $.LeadName %}',
            '{% } %}'
        ]),

        //Localization
        titleText: 'Activities',

        //View Properties
        id: 'activity_list',
        icon: 'content/images/icons/To_Do_24x24.png',
        detailView: 'activity_detail',
        insertView: 'activity_types_list',
        queryOrderBy: 'Timeless desc, StartDate desc',
        querySelect: [
            'Description',
            'StartDate',
            'Type',
            'AccountName',
            'ContactName',
            'LeadId',
            'LeadName',
            'UserId',
            'Timeless'
        ],
        resourceKind: 'activities',

        formatSearchQuery: function(query) {
            return String.format('upper(Description) like "{0}%"', this.escapeSearchQuery(query.toUpperCase()));
        }
    });
})();
<commit_msg>[fixed #1-79669] changed activity list view search to description (contains).<commit_after>/// <reference path="../../../../../argos-sdk/libraries/ext/ext-core-debug.js"/>
/// <reference path="../../../../../argos-sdk/libraries/sdata/sdata-client-debug"/>
/// <reference path="../../../../../argos-sdk/libraries/Simplate.js"/>
/// <reference path="../../../../../argos-sdk/src/View.js"/>
/// <reference path="../../../../../argos-sdk/src/List.js"/>

Ext.namespace("Mobile.SalesLogix.Activity");

(function() {
    Mobile.SalesLogix.Activity.List = Ext.extend(Sage.Platform.Mobile.List, {
        //Templates
        itemTemplate: new Simplate([
            '
',
            '

',
            '{%! $$.contentTemplate %}',
            '
'
        ]),
        activityTimeTemplate: new Simplate([
            '{% if ($.Timeless) { %}',
            'All-Day',
            '{% } else { %}',
            '{%: Mobile.SalesLogix.Format.date($.StartDate, "h:mm") %}',
            ' {%: Mobile.SalesLogix.Format.date($.StartDate, "tt") %},',
            '{% } %}'
        ]),
        contentTemplate: new Simplate([
            '
',
            '{%= $$.activityTimeTemplate.apply($) %}',
            ' {%: $.Description %}',
            '
',
            '
{%: Mobile.SalesLogix.Format.date($.StartDate, "ddd M/d/yy", Sage.Platform.Mobile.Convert.toBoolean($.Timeless)) %} - {%= $$.nameTemplate.apply($) %}
'
        ]),
        nameTemplate: new Simplate([
            '{% if ($.ContactName) { %}',
            '{%: $.ContactName %} / {%: $.AccountName %}',
            '{% } else if ($.AccountName) { %}',
            '{%: $.AccountName %}',
            '{% } else { %}',
            '{%: $.LeadName %}',
            '{% } %}'
        ]),

        //Localization
        titleText: 'Activities',

        //View Properties
        id: 'activity_list',
        icon: 'content/images/icons/To_Do_24x24.png',
        detailView: 'activity_detail',
        insertView: 'activity_types_list',
        queryOrderBy: 'Timeless desc, StartDate desc',
        querySelect: [
            'Description',
            'StartDate',
            'Type',
            'AccountName',
            'ContactName',
            'LeadId',
            'LeadName',
            'UserId',
            'Timeless'
        ],
        resourceKind: 'activities',

        formatSearchQuery: function(query) {
            return String.format('upper(Description) like "%{0}%"', this.escapeSearchQuery(query.toUpperCase()));
        }
    });
})();
<|endoftext|>


<commit_before>$(document).ready(function () {
    $('.input-tags').select2({
        tags: true,
        tokenSeparators: [',']
    })

    $('.select2').select2()

    $('.btn-visit-home').on('click', function (e) {
        e.preventDefault();
        var url = $(this).data('href');
        window.open(url, '_blank');
    })

    $('.btn-delete').on('click', function () {
        return confirm('Are you sure?');
    })

    $('.datetimepicker').datetimepicker({
        format: 'YYYY/MM/DD HH:mm:ss'
    })

    $('.datepicker').datetimepicker({
        format: 'YYYY-MM-DD'
    })

    var updateOutput = function(e)
    {
        var list   = e.length ? e : $(e.target);

        if (window.JSON) {
            return (window.JSON.stringify(list.nestable('serialize')));//, null, 2));
        } else {
            return ('JSON browser support required for this demo.');
        }
    };

    $('#nestable-category').nestable({ /* config options */ })
    $('#nestable-category').on('change', function (e) {
        // var nestable = $(this).nestable('serialize');
        var nestable = updateOutput(e);

        $.ajax({
            url: siteurl + '/kategori/nestable',
            data: {nestable_json: nestable},
            success: function (response) {
                console.log(response)
                // document.write(response)
            }
        })
    })

    // $('.fileinput').on('clear.bs.fileinput', function () {
    //     // $(this).find('input[type=hidden]').val('')
    // })

    // $('.fileinput').on('change.bs.fileinput', function () {
    //     // $(this).find($('[name="remove_featured_image"]')).remove()
    // })

    $('.iframe-btn').fancybox({
        'width'     : 900,
        'height'    : 600,
        'type'      : 'iframe',
        'autoScale' : false,
        fitToView: false,
        autoSize: false,
        autoDimensions: false,
    });

    tinymce.init({
        selector:'.editor',
        plugins: [
                "advlist autolink link image lists charmap print preview hr anchor pagebreak",
                "searchreplace wordcount visualblocks visualchars insertdatetime media nonbreaking",
                "table contextmenu directionality emoticons paste textcolor responsivefilemanager"
        ],
        toolbar1: "undo redo | bold italic underline | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | styleselect",
        toolbar2: "| responsivefilemanager | link unlink anchor | image media | forecolor backcolor  | print preview code ",
        image_advtab: true ,

        external_filemanager_path:baseurl+"filemanager/",
        filemanager_title:"Responsive Filemanager" ,
        external_plugins: { "filemanager" : "./../../../admin/filemanager/plugin.min.js"},
        relative_urls: false,
        remove_script_host : false
    });

    $('.switch-input.ajax').on('change', function () {
        var id      = $(this).val();
        var type    = this.checked ? 'private' : 'public';

        $.ajax({
            url: siteurl + '/article/json/type',
            data: {
                id: id,
                type: type,
            },
            success: function (response) {

            }
        })
    })

    // $('.switch-input.ajax').on('change', function(){
    //     var id      = $(this).val();
    //     var status    = this.checked ? 'unapprove' : 'approve';

    //     $.ajax({
    //         url: siteurl + '/comment/comment_json/status',
    //         data: {
    //             id: id,
    //             status: status,
    //         },
    //         success: function (response){

    //         }
    //     })
    // })

    $('.open-schedule').on('click', function () {
        var input_schedule = $('.input-schedule');
        input_schedule.append('<input type="hidden" name="with_schedule" value="1">')

        input_schedule.show('slow')
    })

    $('.close-schedule').on('click', function () {
        var input_schedule = $('.input-schedule');
        input_schedule.find('[name="with_schedule"]').remove()

        input_schedule.hide('slow')

        return false;
    })

    var url = siteurl + '/user/wilayah';var loading = 'Loading...';
    $(document).ready(function () {
        $('#kota').remoteChained({
            parents: '#provinsi',
            url: url,
            loading : loading
        })

        $('#kecamatan').remoteChained({
            parents: '#provinsi, #kota',
            url: url,
            loading : loading
        })

        $('#desa').remoteChained({
            parents: '#provinsi, #kota, #kecamatan',
            url: url,
            loading : loading
        })
    })
})<commit_msg>Remove line no longer used<commit_after>$(document).ready(function () {
    $('.input-tags').select2({
        tags: true,
        tokenSeparators: [',']
    })

    $('.select2').select2()

    $('.btn-visit-home').on('click', function (e) {
        e.preventDefault();
        var url = $(this).data('href');
        window.open(url, '_blank');
    })

    $('.btn-delete').on('click', function () {
        return confirm('Are you sure?');
    })

    $('.datetimepicker').datetimepicker({
        format: 'YYYY/MM/DD HH:mm:ss'
    })

    $('.datepicker').datetimepicker({
        format: 'YYYY-MM-DD'
    })

    var updateOutput = function(e)
    {
        var list   = e.length ? e : $(e.target);

        if (window.JSON) {
            return (window.JSON.stringify(list.nestable('serialize')));//, null, 2));
        } else {
            return ('JSON browser support required for this demo.');
        }
    };

    $('#nestable-category').nestable({ /* config options */ })
    $('#nestable-category').on('change', function (e) {
        // var nestable = $(this).nestable('serialize');
        var nestable = updateOutput(e);

        $.ajax({
            url: siteurl + '/kategori/nestable',
            data: {nestable_json: nestable},
            success: function (response) {
                console.log(response)
                // document.write(response)
            }
        })
    })

    $('#article').DataTable();
    $('#publish').DataTable();

    $('.iframe-btn').fancybox({
        'width'     : 900,
        'height'    : 600,
        'type'      : 'iframe',
        'autoScale' : false,
        fitToView: false,
        autoSize: false,
        autoDimensions: false,
    });

    tinymce.init({
        selector:'.editor',
        plugins: [
                "advlist autolink link image lists charmap print preview hr anchor pagebreak",
                "searchreplace wordcount visualblocks visualchars insertdatetime media nonbreaking",
                "table contextmenu directionality emoticons paste textcolor responsivefilemanager"
        ],
        toolbar1: "undo redo | bold italic underline | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | styleselect",
        toolbar2: "| responsivefilemanager | link unlink anchor | image media | forecolor backcolor  | print preview code ",
        image_advtab: true ,

        external_filemanager_path:baseurl+"filemanager/",
        filemanager_title:"Responsive Filemanager" ,
        external_plugins: { "filemanager" : "./../../../admin/filemanager/plugin.min.js"},
        relative_urls: false,
        remove_script_host : false
    });

    $('.switch-input.ajax').on('change', function () {
        var id      = $(this).val();
        var type    = this.checked ? 'private' : 'public';

        $.ajax({
            url: siteurl + '/article/json/type',
            data: {
                id: id,
                type: type,
            },
            success: function (response) {

            }
        })
    })

    $('.open-schedule').on('click', function () {
        var input_schedule = $('.input-schedule');
        input_schedule.append('<input type="hidden" name="with_schedule" value="1">')

        input_schedule.show('slow')
    })

    $('.close-schedule').on('click', function () {
        var input_schedule = $('.input-schedule');
        input_schedule.find('[name="with_schedule"]').remove()

        input_schedule.hide('slow')

        return false;
    })

    var url = siteurl + '/user/wilayah';var loading = 'Loading...';
    $(document).ready(function () {
        $('#kota').remoteChained({
            parents: '#provinsi',
            url: url,
            loading : loading
        })

        $('#kecamatan').remoteChained({
            parents: '#provinsi, #kota',
            url: url,
            loading : loading
        })

        $('#desa').remoteChained({
            parents: '#provinsi, #kota, #kecamatan',
            url: url,
            loading : loading
        })
    })
})<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017 Bonnie Schulkin. All Rights Reserved.
 *
 * This file is part of BoxCharter.
 *
 * BoxCharter is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option)
 * any later version.
 *
 * BoxCharter is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with BoxCharter. If not, see <http://www.gnu.org/licenses/>.
 *
 */

/**
 * Tests for the section model.
 * @module section_test
 */
const { createChart } = require('../utilities/create_items')
const { addToDbSuccessTests, addToDbFailTests } = require('../utilities/add_db_tests')
const { Section } = require('../../db/model/section_db')

// //////////////////////////////////////////////////////////////////////////////
// SUCCESS addToDb
// //////////////////////////////////////////////////////////////////////////////

/**
 * Add section
 * @param  {Section}  section - section instance
 * @return {Promise}            Promise resolving to the section's id in the database
 */
const addSection = async (section) => {
  // make a fake chart to insert section into
  const chart = await createChart()
  section.chartId = chart.chartid
  return section.addToDb()
}

const successSections = [
  { descString: 'section with only necessary metadata', item: new Section(null, 0, null, null, 4, 1, null) },
  { descString: 'section with all metadata', item: new Section(null, 1, 'three word name', 'description is this', 4, 3, 2) },
]

const sectionFields = [
  'sectionId',
  'chartId',
  'index',
  'sectionName',
  'sectionDesc',
  'beatsPerMeasure',
  'verseCount',
  'pickupMeasureBeats']

addToDbSuccessTests('section', successSections, sectionFields, addSection)

// //////////////////////////////////////////////////////////////////////////////
// FAILURE addToDb
// //////////////////////////////////////////////////////////////////////////////

/**
 * Preparation function for failure tests
 * @return {Promise} - sectionId for created section
 */
const failPrepare = async () => {
  // make a fake chart to insert section into;
  // assume there will be a chart with id 1 after this
  await createChart()
}

// const failureSections = [
//   { descString: 'the sectionId doesn\'t exist in the db', item: new Section(-1, 0) },
//   { descString: 'the section is missing a sectionId', item: new Section(null, 0) },
//   { descString: 'the section is missing an index', item: new Section(1) },
// ]
//
// addToDbFailTests('section', failureSections, failPrepare)
<commit_msg>Add tests for circumstances under which adding a section should fail.<commit_after>/*
 * Copyright (c) 2017 Bonnie Schulkin. All Rights Reserved.
 *
 * This file is part of BoxCharter.
 *
 * BoxCharter is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option)
 * any later version.
 *
 * BoxCharter is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with BoxCharter. If not, see <http://www.gnu.org/licenses/>.
 *
 */

/**
 * Tests for the section model.
 * @module section_test
 */
const { createChart } = require('../utilities/create_items')
const { addToDbSuccessTests, addToDbFailTests } = require('../utilities/add_db_tests')
const { Section } = require('../../db/model/section_db')

// //////////////////////////////////////////////////////////////////////////////
// SUCCESS addToDb
// //////////////////////////////////////////////////////////////////////////////

/**
 * Add section
 * @param  {Section}  section - section instance
 * @return {Promise}            Promise resolving to the section's id in the database
 */
const addSection = async (section) => {
  // make a fake chart to insert section into
  const chart = await createChart()
  section.chartId = chart.chartid
  return section.addToDb()
}

const successSections = [
  { descString: 'section with only necessary metadata', item: new Section(null, 0, null, null, 4, 1, null) },
  { descString: 'section with all metadata', item: new Section(null, 1, 'three word name', 'description is this', 4, 3, 2) },
]

const sectionFields = [
  'sectionId',
  'chartId',
  'index',
  'sectionName',
  'sectionDesc',
  'beatsPerMeasure',
  'verseCount',
  'pickupMeasureBeats']

addToDbSuccessTests('section', successSections, sectionFields, addSection)

// //////////////////////////////////////////////////////////////////////////////
// FAILURE addToDb
// //////////////////////////////////////////////////////////////////////////////

/**
 * Preparation function for failure tests
 * @return {Promise} - sectionId for created section
 */
const failPrepare = async () => {
  // make a fake chart to insert section into;
  // assume there will be a chart with id 1 after this
  await createChart()
}

const failureSections = [
  { descString: 'the chartId doesn\'t exist in the db', item: new Section(-1, 0, null, null, 4, 1, null) },
  { descString: 'the section is missing a chartId', item: new Section(null, 0, null, null, 4, 1, null) },
  { descString: 'the section is missing an index', item: new Section(1, null, null, null, 4, 1, null) },
  { descString: 'the section is missing beatsPerMeasure', item: new Section(1, 0, null, null, null, 1, null) },
  { descString: 'the section is missing verseCount', item: new Section(1, 0, null, null, 4, null, null) },
]

addToDbFailTests('section', failureSections, failPrepare)
<|endoftext|>


<commit_before>jQuery(document).ready(function() {

    $.extend( $.ui.autocomplete.prototype, {

    	_renderItem: function( ul, item) {
    	  var list = "

"
    	  if (item.clazz) {
    	    list = "

"
    	  }
        return $( list )
          .data( "item.autocomplete", item )
          .append( $( "" ).html( item.html || item.label ) )
          .appendTo( ul );
      }
    });

    var precooked = null;

    $.ajax( {
      url: "/search/precooked",
      dataType: "jsonp",
      jsonpCallback: "precookedf",
      cache: true,
      success: function(data) {
        precooked = data;
      }
    });

    // //setup search hint items
    // $('.search_hint_item').click(
    //     function(item){
    //         $('#main_autocomplete').val($(this).text());
    //     }
    // );

    var search_box_default_text="I’m looking for…";
    //search hint
    //
    $('#main_autocomplete').val(search_box_default_text);

    $('#main_autocomplete').blur(
      function(){
        if ($('#main_autocomplete').val() == "") {
          $('#main_autocomplete').val(search_box_default_text);
        }
      }
    );

    $('#main_autocomplete').focus(
      function(){
        if ($('#main_autocomplete').val() == search_box_default_text) {
          $('#main_autocomplete').val("");
        }
      }
    );

    var filter_terms = function(search_term,data) {
       var highlight_term = function(string,term) {
              html_safe = html_escape(string);
              var terms = term.split(' ');
              for (var i in terms)  {
                var clean_term = html_escape(terms[i].replace(/^\s+|\s+$/g, ''));
                if (clean_term != "") {
                  var regex = new RegExp("\\b("+clean_term+")","ig");
                  html_safe = html_safe.replace(regex,'$1');
                }
              }
              return html_safe;
        };

       return $.map(data, function(item) {
          return {
              label: html_escape(item.label),
              html:  highlight_term(item.label,search_term),
              url:   item.url
          };
       });
    }

    var track_search = function(type,label) {
       var _gaq = _gaq || [];
       _gaq.push( ['_trackEvent', 'Search', type, label]);
    };

    var html_escape = function( string) {
        return $('
').text(string).html();
    };

    $("#main_autocomplete").parent("form").submit(function() {
      $('li.search-site a').addClass("ui-state-hover");
      $('li.search-site a').css('color', '#000');
      track_search("query", $("#main_autocomplete").val());
      return true;
    });

    $("#main_autocomplete").autocomplete({
        delay: 0,
        source: function( request, response ) {

          var search_site = function(search_term) {
            return {
                label: "Search for "+html_escape(search_term),
                html:  "Search for "+html_escape(search_term)+"",
                url:   "/search?q="+encodeURIComponent(search_term),
                clazz: "search-site"
              };
          };

          var loading = function(term) {
            var data = [];
            if (precooked) {
              if (precooked[term]) {
                data = filter_terms(term,precooked[term]);
              }
            }
            data.push(search_site(request.term));
            response(data);
          };

          var ajax = function() {
            $.ajax({
              url: "/search/autocomplete",
              dataType: "jsonp",
              jsonpCallback: "search_received",
              data: { term: request.term },
              cache: true,
              success: function( data ) {
                var search_term = request.term;
                data = filter_terms(search_term,data.slice(0,10));
                data.push(search_site(search_term));
                response( data );
              }
            });
          };

          term = request.term;
          if (term.length == 0) {
            response([]);
          } else if (term.length == 1) {
            loading(term);
          } else {
            ajax();
          }

        },
        select: function(event, ui) {
          track_search("select",ui.item.label);
          location.href = ui.item.url
        },
        // open: function(event, ui){
        //    console.debug(event);
        // }
    });

});
<commit_msg>Try a different way of tracking searches<commit_after>jQuery(document).ready(function() {

    $.extend( $.ui.autocomplete.prototype, {

    	_renderItem: function( ul, item) {
    	  var list = "

"
    	  if (item.clazz) {
    	    list = "

"
    	  }
        return $( list )
          .data( "item.autocomplete", item )
          .append( $( "" ).html( item.html || item.label ) )
          .appendTo( ul );
      }
    });

    var precooked = null;

    $.ajax( {
      url: "/search/precooked",
      dataType: "jsonp",
      jsonpCallback: "precookedf",
      cache: true,
      success: function(data) {
        precooked = data;
      }
    });

    // //setup search hint items
    // $('.search_hint_item').click(
    //     function(item){
    //         $('#main_autocomplete').val($(this).text());
    //     }
    // );

    var search_box_default_text="I’m looking for…";
    //search hint
    //
    $('#main_autocomplete').val(search_box_default_text);

    $('#main_autocomplete').blur(
      function(){
        if ($('#main_autocomplete').val() == "") {
          $('#main_autocomplete').val(search_box_default_text);
        }
      }
    );

    $('#main_autocomplete').focus(
      function(){
        if ($('#main_autocomplete').val() == search_box_default_text) {
          $('#main_autocomplete').val("");
        }
      }
    );

    var filter_terms = function(search_term,data) {
       var highlight_term = function(string,term) {
              html_safe = html_escape(string);
              var terms = term.split(' ');
              for (var i in terms)  {
                var clean_term = html_escape(terms[i].replace(/^\s+|\s+$/g, ''));
                if (clean_term != "") {
                  var regex = new RegExp("\\b("+clean_term+")","ig");
                  html_safe = html_safe.replace(regex,'$1');
                }
              }
              return html_safe;
        };

       return $.map(data, function(item) {
          return {
              label: html_escape(item.label),
              html:  highlight_term(item.label,search_term),
              url:   item.url
          };
       });
    }

    var track_search = function(type,label) {
       if (_gaq != undefined) {
        _gaq.push( ['_trackEvent', 'Search', type, label]);
       }
    };

    var html_escape = function( string) {
        return $('
').text(string).html();
    };

    $("#main_autocomplete").parent("form").submit(function() {
      $('li.search-site a').addClass("ui-state-hover");
      $('li.search-site a').css('color', '#000');
      track_search("query", $("#main_autocomplete").val());
      return true;
    });

    $("#main_autocomplete").autocomplete({
        delay: 0,
        source: function( request, response ) {

          var search_site = function(search_term) {
            return {
                label: "Search for "+html_escape(search_term),
                html:  "Search for "+html_escape(search_term)+"",
                url:   "/search?q="+encodeURIComponent(search_term),
                clazz: "search-site"
              };
          };

          var loading = function(term) {
            var data = [];
            if (precooked) {
              if (precooked[term]) {
                data = filter_terms(term,precooked[term]);
              }
            }
            data.push(search_site(request.term));
            response(data);
          };

          var ajax = function() {
            $.ajax({
              url: "/search/autocomplete",
              dataType: "jsonp",
              jsonpCallback: "search_received",
              data: { term: request.term },
              cache: true,
              success: function( data ) {
                var search_term = request.term;
                data = filter_terms(search_term,data.slice(0,10));
                data.push(search_site(search_term));
                response( data );
              }
            });
          };

          term = request.term;
          if (term.length == 0) {
            response([]);
          } else if (term.length == 1) {
            loading(term);
          } else {
            ajax();
          }

        },
        select: function(event, ui) {
          track_search("select",ui.item.label);
          location.href = ui.item.url
        },
        // open: function(event, ui){
        //    console.debug(event);
        // }
    });

});
<|endoftext|>


<commit_before>$(document).ready(function() {
  am4core.useTheme(am4themes_material);
  am4core.useTheme(am4themes_animated);

  recordChart()
  locationChart()
  hostChart()
});

function recordChart(){
  var chart = am4core.create("recordChart", am4charts.XYChart);
  chart.paddingRight = 20;

  // Add data
  chart.data = [{
    "year": "2018-10-23",
    "value": 657296
  }, {
    "year": "2018-12-23",
    "value": 692743
  }, {
    "year": "2019-02-23",
    "value": 707271
  }, {
    "year": "2019-04-23",
    "value": 734704
  }, {
    "year": "2019-06-23",
    "value": 758056
  }, {
    "year": "2019-08-23",
    "value": 780274
  }, {
    "year": "2019-10-23",
    "value": 787671
  }
  ];

  // Create axes
  var categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
  categoryAxis.dataFields.category = "year";
  categoryAxis.renderer.minGridDistance = 50;
  categoryAxis.renderer.grid.template.location = 0.5;
  categoryAxis.startLocation = 0.5;
  categoryAxis.endLocation = 0.5;

  // Create value axis
  var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
  valueAxis.baseValue = 0;

  // Create series
  var series = chart.series.push(new am4charts.LineSeries());
  series.dataFields.valueY = "value";
  series.dataFields.categoryX = "year";
  series.strokeWidth = 2;
  series.minBulletDistance = 15;
  series.tooltipText = "{valueY}";
  series.tooltip.pointerOrientation = "vertical";
  series.tooltip.background.fillOpacity = 0.5;
  series.tooltip.label.padding(12,12,12,12)
  series.stroke = am4core.color("#D65DB1");

  var bullet = series.bullets.push(new am4charts.CircleBullet());
  bullet.circle.strokeWidth = 2;
  bullet.circle.radius = 4;
  bullet.circle.fill = am4core.color("#fff");

  var bullethover = bullet.states.create("hover");
  bullethover.properties.scale = 1.3;

  var range = valueAxis.createSeriesRange(series);
  range.value = 0;
  range.endValue = 1000;
  range.contents.stroke = am4core.color("#FF0000");
  range.contents.fill = range.contents.stroke;

  var label = categoryAxis.renderer.labels.template;
  label.wrap = true;
  label.minWidth = 150

  chart.cursor = new am4charts.XYCursor();
}

function locationChart(){
  // Create chart instance
  var chart = am4core.create("locationChart", am4charts.XYChart);
  chart.paddingRight = 20;

  // Add data
  chart.data = [{
    "year": "2018-10-23",
    "value": 624801
  }, {
    "year": "2018-12-23",
    "value": 686272
  }, {
    "year": "2019-02-23",
    "value": 700798
  }, {
    "year": "2019-04-23",
    "value": 728231
  }, {
    "year": "2019-06-23",
    "value": 751583
  }, {
    "year": "2019-08-23",
    "value": 773800
  }, {
    "year": "2019-10-23",
    "value": 781195
  }
  ];

  // Create axes
  var categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
  categoryAxis.dataFields.category = "year";
  categoryAxis.renderer.minGridDistance = 50;
  categoryAxis.renderer.grid.template.location = 0.5;
  categoryAxis.startLocation = 0.5;
  categoryAxis.endLocation = 0.5;

  // Create value axis
  var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
  valueAxis.baseValue = 0;

  // Create series
  var series = chart.series.push(new am4charts.LineSeries());
  series.dataFields.valueY = "value";
  series.dataFields.categoryX = "year";
  series.strokeWidth = 2;
  series.minBulletDistance = 15;
  series.tooltipText = "{valueY}";
  series.tooltip.pointerOrientation = "vertical";
  series.tooltip.background.fillOpacity = 0.5;
  series.tooltip.label.padding(12,12,12,12)

  var bullet = series.bullets.push(new am4charts.CircleBullet());
  bullet.circle.strokeWidth = 2;
  bullet.circle.radius = 4;
  bullet.circle.fill = am4core.color("#fff");

  var bullethover = bullet.states.create("hover");
  bullethover.properties.scale = 1.3;

  var range = valueAxis.createSeriesRange(series);
  range.value = 0;
  range.endValue = 1000;
  range.contents.stroke = am4core.color("#FF0000");
  range.contents.fill = range.contents.stroke;

  var label = categoryAxis.renderer.labels.template;
  label.wrap = true;
  label.minWidth = 150

  chart.cursor = new am4charts.XYCursor();
}

function hostChart(){
  var chart = am4core.create("hostChart", am4charts.XYChart);
  chart.paddingRight = 20;

  chart.data = [{
    "year": "2018-10-23",
    "value": 614012
  }, {
    "year": "2018-12-23",
    "value": 634171
  }, {
    "year": "2019-02-23",
    "value": 648019
  }, {
    "year": "2019-04-23",
    "value": 683538
  }, {
    "year": "2019-06-23",
    "value": 708993
  }, {
    "year": "2019-08-23",
    "value": 731934
  }, {
    "year": "2019-10-23",
    "value": 739280
  }
  ];

  // Create axes
  var categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
  categoryAxis.dataFields.category = "year";
  categoryAxis.renderer.minGridDistance = 50;
  categoryAxis.renderer.grid.template.location = 0.5;
  categoryAxis.startLocation = 0.5;
  categoryAxis.endLocation = 0.5;

  // Create value axis
  var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
  valueAxis.baseValue = 0;

  // Create series
  var series = chart.series.push(new am4charts.LineSeries());
  series.dataFields.valueY = "value";
  series.dataFields.categoryX = "year";
  series.strokeWidth = 2;
  series.minBulletDistance = 15;
  series.tooltipText = "{valueY}";
  series.tooltip.pointerOrientation = "vertical";
  series.tooltip.background.fillOpacity = 0.5;
  series.tooltip.label.padding(12,12,12,12)
  series.stroke = am4core.color("#FF6F91");

  var bullet = series.bullets.push(new am4charts.CircleBullet());
  bullet.circle.strokeWidth = 2;
  bullet.circle.radius = 4;
  bullet.circle.fill = am4core.color("#fff");

  var bullethover = bullet.states.create("hover");
  bullethover.properties.scale = 1.3;

  var range = valueAxis.createSeriesRange(series);
  range.value = 0;
  range.endValue = 1000;
  range.contents.stroke = am4core.color("#FF0000");
  range.contents.fill = range.contents.stroke;

  var label = categoryAxis.renderer.labels.template;
  label.wrap = true;
  label.minWidth = 150

  chart.cursor = new am4charts.XYCursor();
}<commit_msg>update counts<commit_after>$(document).ready(function() {
  am4core.useTheme(am4themes_material);
  am4core.useTheme(am4themes_animated);

  recordChart()
  locationChart()
  hostChart()
});

function recordChart(){
  var chart = am4core.create("recordChart", am4charts.XYChart);
  chart.paddingRight = 20;

  // Add data
  chart.data = [{
    "year": "2018-10-23",
    "value": 657296
  }, {
    "year": "2018-12-23",
    "value": 692743
  }, {
    "year": "2019-02-23",
    "value": 707271
  }, {
    "year": "2019-04-23",
    "value": 734704
  }, {
    "year": "2019-06-23",
    "value": 758056
  }, {
    "year": "2019-08-23",
    "value": 780274
  }, {
    "year": "2019-10-23",
    "value": 787671
  }, {
    "year": "2020-02-23",
    "value": 826088
  }
  ];

  // Create axes
  var categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
  categoryAxis.dataFields.category = "year";
  categoryAxis.renderer.minGridDistance = 50;
  categoryAxis.renderer.grid.template.location = 0.5;
  categoryAxis.startLocation = 0.5;
  categoryAxis.endLocation = 0.5;

  // Create value axis
  var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
  valueAxis.baseValue = 0;

  // Create series
  var series = chart.series.push(new am4charts.LineSeries());
  series.dataFields.valueY = "value";
  series.dataFields.categoryX = "year";
  series.strokeWidth = 2;
  series.minBulletDistance = 15;
  series.tooltipText = "{valueY}";
  series.tooltip.pointerOrientation = "vertical";
  series.tooltip.background.fillOpacity = 0.5;
  series.tooltip.label.padding(12,12,12,12)
  series.stroke = am4core.color("#D65DB1");

  var bullet = series.bullets.push(new am4charts.CircleBullet());
  bullet.circle.strokeWidth = 2;
  bullet.circle.radius = 4;
  bullet.circle.fill = am4core.color("#fff");

  var bullethover = bullet.states.create("hover");
  bullethover.properties.scale = 1.3;

  var range = valueAxis.createSeriesRange(series);
  range.value = 0;
  range.endValue = 1000;
  range.contents.stroke = am4core.color("#FF0000");
  range.contents.fill = range.contents.stroke;

  var label = categoryAxis.renderer.labels.template;
  label.wrap = true;
  label.minWidth = 150

  chart.cursor = new am4charts.XYCursor();
}

function locationChart(){
  // Create chart instance
  var chart = am4core.create("locationChart", am4charts.XYChart);
  chart.paddingRight = 20;

  // Add data
  chart.data = [{
    "year": "2018-10-23",
    "value": 624801
  }, {
    "year": "2018-12-23",
    "value": 686272
  }, {
    "year": "2019-02-23",
    "value": 700798
  }, {
    "year": "2019-04-23",
    "value": 728231
  }, {
    "year": "2019-06-23",
    "value": 751583
  }, {
    "year": "2019-08-23",
    "value": 773800
  }, {
    "year": "2019-10-23",
    "value": 781195
  }, {
    "year": "2020-02-23",
    "value": 792166
  }
  ];

  // Create axes
  var categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
  categoryAxis.dataFields.category = "year";
  categoryAxis.renderer.minGridDistance = 50;
  categoryAxis.renderer.grid.template.location = 0.5;
  categoryAxis.startLocation = 0.5;
  categoryAxis.endLocation = 0.5;

  // Create value axis
  var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
  valueAxis.baseValue = 0;

  // Create series
  var series = chart.series.push(new am4charts.LineSeries());
  series.dataFields.valueY = "value";
  series.dataFields.categoryX = "year";
  series.strokeWidth = 2;
  series.minBulletDistance = 15;
  series.tooltipText = "{valueY}";
  series.tooltip.pointerOrientation = "vertical";
  series.tooltip.background.fillOpacity = 0.5;
  series.tooltip.label.padding(12,12,12,12)

  var bullet = series.bullets.push(new am4charts.CircleBullet());
  bullet.circle.strokeWidth = 2;
  bullet.circle.radius = 4;
  bullet.circle.fill = am4core.color("#fff");

  var bullethover = bullet.states.create("hover");
  bullethover.properties.scale = 1.3;

  var range = valueAxis.createSeriesRange(series);
  range.value = 0;
  range.endValue = 1000;
  range.contents.stroke = am4core.color("#FF0000");
  range.contents.fill = range.contents.stroke;

  var label = categoryAxis.renderer.labels.template;
  label.wrap = true;
  label.minWidth = 150

  chart.cursor = new am4charts.XYCursor();
}

function hostChart(){
  var chart = am4core.create("hostChart", am4charts.XYChart);
  chart.paddingRight = 20;

  chart.data = [{
    "year": "2018-10-23",
    "value": 614012
  }, {
    "year": "2018-12-23",
    "value": 634171
  }, {
    "year": "2019-02-23",
    "value": 648019
  }, {
    "year": "2019-04-23",
    "value": 683538
  }, {
    "year": "2019-06-23",
    "value": 708993
  }, {
    "year": "2019-08-23",
    "value": 731934
  }, {
    "year": "2019-10-23",
    "value": 739280
  }, {
    "year": "2020-02-23",
    "value": 777473
  }
  ];

  // Create axes
  var categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
  categoryAxis.dataFields.category = "year";
  categoryAxis.renderer.minGridDistance = 50;
  categoryAxis.renderer.grid.template.location = 0.5;
  categoryAxis.startLocation = 0.5;
  categoryAxis.endLocation = 0.5;

  // Create value axis
  var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
  valueAxis.baseValue = 0;

  // Create series
  var series = chart.series.push(new am4charts.LineSeries());
  series.dataFields.valueY = "value";
  series.dataFields.categoryX = "year";
  series.strokeWidth = 2;
  series.minBulletDistance = 15;
  series.tooltipText = "{valueY}";
  series.tooltip.pointerOrientation = "vertical";
  series.tooltip.background.fillOpacity = 0.5;
  series.tooltip.label.padding(12,12,12,12)
  series.stroke = am4core.color("#FF6F91");

  var bullet = series.bullets.push(new am4charts.CircleBullet());
  bullet.circle.strokeWidth = 2;
  bullet.circle.radius = 4;
  bullet.circle.fill = am4core.color("#fff");

  var bullethover = bullet.states.create("hover");
  bullethover.properties.scale = 1.3;

  var range = valueAxis.createSeriesRange(series);
  range.value = 0;
  range.endValue = 1000;
  range.contents.stroke = am4core.color("#FF0000");
  range.contents.fill = range.contents.stroke;

  var label = categoryAxis.renderer.labels.template;
  label.wrap = true;
  label.minWidth = 150

  chart.cursor = new am4charts.XYCursor();
}<|endoftext|>


<commit_before>/**
 * index.js - Main library for index page/view.
 * Authors: Ian McGaunn; Dave Zimmelman
 * Modified: 09 Mar 15
 */
(function (window, $) {
    'use strict';

    function insertPodcasts(pcasts, selector, append, fav) {
        var i;
        if (!append) $(selector).html('');
        for (i in pcasts) {
            var classes = (fav) ? "castnail favorite" : "castnail";
            $(selector).append('

');
        }
    }

    /**
     * Populate results table with search data.
     * @param {Object} data - The JSON object returned from iTunes query.
     */
    function searchResults(results) {
        var podcast, row, count;
        // Update table title with result count.
        if (results.length > 0) {
            $('#result-counter').html(results.length + " Results");
            $('#search-results').css('height', '120px');
            $('#search-results').css('padding', '10px');
        } else {
            $('#result-counter').html("No Results");
            $('#search-results').css('height', '0px');
            $('#search-results').css('padding', '0px');
        }
        insertPodcasts(results, '#search-results');
        /*
        // Remove existing results.
        $('#results-table tbody > tr').remove();
        // Add entry for each podcast.
        for (podcast in results) {
            row = $('
');
            row.append($('').html(''));
            row.append($('').text(results[podcast].title));
            row.append($('').text(results[podcast].genre));
            $('#results-table').append(row);
        }
        // Temporary system for getting to feed pages
        $('.feed-row').click(function () {
            var id = $(this).data('id');
            window.location = '/podcast/' + id;
        });*/
    }

    /**
     * Populate results table with browse data.
     * @param {Object} data - The JSON object returned from iTunes query.
     */
    function browseResults(data) {
        var results = data.feed.entry, podcast, row, count;
        // Update table title with result count.
        count = (results.length > 0) ? "" + results.length : "No";
        $('#right-col > h3').html(count + " Results");
        // Remove existing results.
        $('#results-table tbody > tr').remove();
        // Add entry for each podcast.
        for (podcast in results) {
            row = $('
');
            row.append($('').html(''));
            row.append($('').text(results[podcast]['im:name'].label));
            row.append($('').text(results[podcast].category.attributes.label));
            $('#results-table').append(row);
        }
        // Temporary system for getting to feed pages
        $('.feed-row').click(function () {
            var id = $(this).data('id');
            window.location = '/podcast/' + id;
        });
    }

    /* When document is finished loading, execute following code: */
    $().ready(function () {

        // Check for search or browse data passed from server.
        //  This is for cached data only.
        if (typeof(presearch) !== "undefined") {
            searchResults(presearch);
        }
        else if (typeof(prebrowse) !== "undefined") {
            browseResults(prebrowse);
        }

        // Submit search query
        var submitSearch = function () {
            clearInterval(searchBoxTH);
            searchBoxTH = null;
            var searchTerm = $('#podcast-search-input').val();
            // Get search data from API.
            $.get('/api/search/?term=' + searchTerm, function (data) {
                // Parse results and add to table.
                searchResults(data);
                // Push new URL state.
                window.history.pushState({}, document.title, '/search/' + searchTerm);
            });
        };
        // Search box change
        var quicksearch = function () {
            var s = $('#podcast-search-input').val().trim();
            if (s == lastTickSearch) {
                clearInterval(searchBoxTH);
                searchBoxTH = null;
                return;
            }
            if (s != "") {
                lastTickSearch = s;
                $.get('/api/quicksearch/?term=' + s, function (data) {
                    searchResults(data);
                });
            }
        };
        var searchBoxTH = null;
        var lastTickSearch = "";

        // Reload page when user goes forward or back to process cached search or browse results.
        window.onpopstate = function(event) {
            window.location = document.location;
        };

        $.get('/api/view/splash', function (data) {

            $('#left-col').html(data);

            $.get('/api/castcat/0', function (data) {
                insertPodcasts(data.podcasts, '#pc-0 > .panel-body', false, false);
            });
            $('#left-col .genre-panel').each(function () {
                var i, el = $(this).find('.panel-body'), gid = $(this).data('genreid');
                $.get('/api/castcat/' + gid, function (data) {
                    el.html('');
                    if (data.favorites) {
                        insertPodcasts(data.favorites, el, false, true);
                    }
                    insertPodcasts(data.podcasts, el, false, false);
                });
            });

            $('#podcast-search-input').on('change keyup paste', function (e) {
                if (e.type == "keyup" && e.which == 13) {
                    // Enter key pressed
                    submitSearch();
                }
                else if ($(this).val().trim() !== "" &&
                         $(this).val().trim() !== lastTickSearch &&
                         searchBoxTH === null) {
                    quicksearch();
                    searchBoxTH = setInterval(quicksearch, 1000);
                }
                else if ($(this).val().trim() === "") {
                    clearInterval(searchBoxTH);
                    searchBoxTH = null;
                    searchResults({});
                }
            });
            // Search button press
            $('#podcast-search-button').click(function () {
                submitSearch();
            });

            // Browse submission
            $('#podcast-browse').submit(function () {
                var genre = $('#podcast-browse-cat').val();
                // Get browse data from API.
                $.get('/api/browse/?limit=10&genre=' + genre, function (data) {
                    // Parse results and add to table.
                    browseResults(JSON.parse(data));
                    // Push new URL state.
                    window.history.pushState({}, document.title, '/browse/' + genre);
                });
            });
        });

    });
}(window, jQuery));
<commit_msg>[Fix] Script<commit_after>/**
 * index.js - Main library for index page/view.
 * Authors: Ian McGaunn; Dave Zimmelman
 * Modified: 09 Mar 15
 */
(function (window, $) {
    'use strict';

    function insertPodcasts(pcasts, selector, append, fav) {
        var i;
        if (!append) $(selector).html('');
        for (i in pcasts) {
            var classes = (fav) ? "castnail favorite" : "castnail";
            $(selector).append('

');
        }
    }

    /**
     * Populate results table with search data.
     * @param {Object} data - The JSON object returned from iTunes query.
     */
    function searchResults(results) {
        var podcast, row, count;
        // Update table title with result count.
        if (results.length > 0) {
            $('#result-counter').html(results.length + " Results");
            $('#search-results').css('height', '120px');
            $('#search-results').css('padding', '10px');
        } else {
            $('#result-counter').html("No Results");
            $('#search-results').css('height', '0px');
            $('#search-results').css('padding', '0px');
        }
        insertPodcasts(results, '#search-results');
        /*
        // Remove existing results.
        $('#results-table tbody > tr').remove();
        // Add entry for each podcast.
        for (podcast in results) {
            row = $('
');
            row.append($('').html(''));
            row.append($('').text(results[podcast].title));
            row.append($('').text(results[podcast].genre));
            $('#results-table').append(row);
        }
        // Temporary system for getting to feed pages
        $('.feed-row').click(function () {
            var id = $(this).data('id');
            window.location = '/podcast/' + id;
        });*/
    }

    /**
     * Populate results table with browse data.
     * @param {Object} data - The JSON object returned from iTunes query.
     */
    function browseResults(data) {
        var results = data.feed.entry, podcast, row, count;
        // Update table title with result count.
        count = (results.length > 0) ? "" + results.length : "No";
        $('#right-col > h3').html(count + " Results");
        // Remove existing results.
        $('#results-table tbody > tr').remove();
        // Add entry for each podcast.
        for (podcast in results) {
            row = $('
');
            row.append($('').html(''));
            row.append($('').text(results[podcast]['im:name'].label));
            row.append($('').text(results[podcast].category.attributes.label));
            $('#results-table').append(row);
        }
        // Temporary system for getting to feed pages
        $('.feed-row').click(function () {
            var id = $(this).data('id');
            window.location = '/podcast/' + id;
        });
    }

    /* When document is finished loading, execute following code: */
    $().ready(function () {

        // Check for search or browse data passed from server.
        //  This is for cached data only.
        if (typeof(presearch) !== "undefined") {
            searchResults(presearch);
        }
        else if (typeof(prebrowse) !== "undefined") {
            browseResults(prebrowse);
        }

        // Submit search query
        var submitSearch = function () {
            clearInterval(searchBoxTH);
            searchBoxTH = null;
            var searchTerm = $('#podcast-search-input').val();
            // Get search data from API.
            $.get('/api/search/?term=' + searchTerm, function (data) {
                // Parse results and add to table.
                searchResults(data);
                // Push new URL state.
                window.history.pushState({}, document.title, '/search/' + searchTerm);
            });
        };
        // Search box change
        var quicksearch = function () {
            var s = $('#podcast-search-input').val().trim();
            if (s == lastTickSearch) {
                clearInterval(searchBoxTH);
                searchBoxTH = null;
                return;
            }
            if (s != "") {
                lastTickSearch = s;
                $.get('/api/quicksearch/?term=' + s, function (data) {
                    searchResults(data);
                });
            }
        };
        var searchBoxTH = null;
        var lastTickSearch = "";

        // Reload page when user goes forward or back to process cached search or browse results.
        window.onpopstate = function(event) {
            window.location = document.location;
        };

        $.get('/api/view/splash', function (data) {

            $('#left-col').html(data);

            $.get('/api/castcat/0', function (data) {
                insertPodcasts(data.podcasts, '#pc-0 > .panel-body', false, false);
            });
            $('#left-col .genre-panel').each(function () {
                var i, el = $(this).find('.panel-body'), gid = $(this).data('genreid');
                $.get('/api/castcat/' + gid, function (data) {
                    el.html('');
                    if (data.favorites) {
                        insertPodcasts(data.favorites, el, false, true);
                    }
                    insertPodcasts(data.podcasts, el, false, false);
                });
            });

            $('#podcast-search-input').on('change keyup paste', function (e) {
                if (e.type == "keyup" && e.which == 13) {
                    // Enter key pressed
                    submitSearch();
                }
                else if ($(this).val().trim() !== "" &&
                         $(this).val().trim() !== lastTickSearch &&
                         searchBoxTH === null) {
                    quicksearch();
                    searchBoxTH = setInterval(quicksearch, 1000);
                }
                else if ($(this).val().trim() === "") {
                    clearInterval(searchBoxTH);
                    searchBoxTH = null;
                    searchResults({});
                }
            });
            // Search button press
            $('#podcast-search-button').click(function () {
                submitSearch();
            });

            // Browse submission
            $('#podcast-browse').submit(function () {
                var genre = $('#podcast-browse-cat').val();
                // Get browse data from API.
                $.get('/api/browse/?limit=10&genre=' + genre, function (data) {
                    // Parse results and add to table.
                    browseResults(JSON.parse(data));
                    // Push new URL state.
                    window.history.pushState({}, document.title, '/browse/' + genre);
                });
            });
        });

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


<commit_before>// Copyright 2015 Volker Sorge
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview A table walker.
 *
 * @author volker.sorge@gmail.com (Volker Sorge)
 */

goog.provide('sre.TableWalker');

goog.require('sre.Focus');
goog.require('sre.Levels');
goog.require('sre.SyntaxWalker');
goog.require('sre.WalkerUtil');

/**
 * @constructor
 * @extends {sre.SyntaxWalker}
 * @override
 */
sre.TableWalker = function(node, generator, highlighter, xml) {
  sre.TableWalker.base(this, 'constructor', node, generator, highlighter, xml);

  /**
   * @type {boolean}
   */
  this.modifier = false;

  this.keyMapping[sre.EventUtil.KeyCode['0']] = goog.bind(this.jumpCell, this);
  this.keyMapping[sre.EventUtil.KeyCode['1']] = goog.bind(this.jumpCell, this);
  this.keyMapping[sre.EventUtil.KeyCode['2']] = goog.bind(this.jumpCell, this);
  this.keyMapping[sre.EventUtil.KeyCode['3']] = goog.bind(this.jumpCell, this);
  this.keyMapping[sre.EventUtil.KeyCode['4']] = goog.bind(this.jumpCell, this);
  this.keyMapping[sre.EventUtil.KeyCode['5']] = goog.bind(this.jumpCell, this);
  this.keyMapping[sre.EventUtil.KeyCode['6']] = goog.bind(this.jumpCell, this);
  this.keyMapping[sre.EventUtil.KeyCode['7']] = goog.bind(this.jumpCell, this);
  this.keyMapping[sre.EventUtil.KeyCode['8']] = goog.bind(this.jumpCell, this);
  this.keyMapping[sre.EventUtil.KeyCode['9']] = goog.bind(this.jumpCell, this);
  // this.keyMapping[sre.EventUtil.KeyCode['U']] = goog.bind(this.backJump, this);

  /**
   * @type {?sre.EventUtil.KeyCode}
   */
  this.key = null;

  /**
   * @type {number}
   * @private
   */
  this.row_ = 0;

  // /**
  //  * @type {Array.<number>}
  //  */
  // this.cell = null;

  // /**
  //  * @type {!sre.Levels<string>}
  //  */
  // this.undoStack = new sre.Levels();

  // this.undoFocus = null;

  this.currentTable = null;

};
goog.inherits(sre.TableWalker, sre.SyntaxWalker);

/**
 * @override
 */
sre.TableWalker.prototype.move = function(key) {
  this.key = key;
  var result = sre.TableWalker.base(this, 'move', key);
  this.modifier = false;
  return result;
};

/**
 * @override
 */
sre.TableWalker.prototype.up = function() {
  this.moved = sre.Walker.move.UP;
  return this.eligibleCell_() ?
      this.verticalMove_(false) :
      sre.TableWalker.base(this, 'up');
};

/**
 * @override
 */
sre.TableWalker.prototype.down = function() {
  this.moved = sre.Walker.move.DOWN;
  return this.eligibleCell_() ?
      this.verticalMove_(true) :
      sre.TableWalker.base(this, 'down');
};

/**
 * @type {Array.<sre.SemanticAttr.Role>}
 */
sre.TableWalker.ELIGIBLE_CELL_ROLES = [
  sre.SemanticAttr.Role.DETERMINANT,
  sre.SemanticAttr.Role.ROWVECTOR,
  sre.SemanticAttr.Role.BINOMIAL,
  sre.SemanticAttr.Role.SQUAREMATRIX,
  sre.SemanticAttr.Role.MULTILINE,
  sre.SemanticAttr.Role.MATRIX,
  sre.SemanticAttr.Role.VECTOR,
  sre.SemanticAttr.Role.CASES,
  sre.SemanticAttr.Role.TABLE
];

/**
 * @type {Array.<sre.SemanticAttr.Type>}
 */
sre.TableWalker.ELIGIBLE_TABLE_TYPES = [
  sre.SemanticAttr.Type.MULTILINE,
  sre.SemanticAttr.Type.MATRIX,
  sre.SemanticAttr.Type.VECTOR,
  sre.SemanticAttr.Type.CASES,
  sre.SemanticAttr.Type.TABLE
  //
  // TODO: These two could be useful for the general check!
  // For now omitted.
  //
  // sre.SemanticAttr.Type.ROW,
  // sre.SemanticAttr.Type.CELL
];

/**
 * @return {boolean} True if the focused is an eligible table cell.
 * @private
 */
sre.TableWalker.prototype.eligibleCell_ = function() {
  var primary = this.getFocus().getSemanticPrimary();
  return this.modifier &&
        primary.type === sre.SemanticAttr.Type.CELL &&
    sre.TableWalker.ELIGIBLE_CELL_ROLES.indexOf(primary.role) !== -1;
};

/**
 * Performs a vertical move in a table.
 * @param {boolean} direction If true walk down, o/w up.
 * @return {?sre.Focus} The new focus.
 * @private
 */
sre.TableWalker.prototype.verticalMove_ = function(direction) {
  var parent = this.previousLevel();
  if (!parent) return null;
  var origFocus = this.getFocus();
  var origIndex = /** @type {number} */(
      this.levels.indexOf(this.primaryId()));
  var origLevel = this.levels.pop();
  var parentIndex = /** @type {number} */(
      this.levels.indexOf(parent));
  var row = /** @type {string} */(this.levels.get(
      direction ? parentIndex + 1 : parentIndex - 1));
  if (!row) {
    this.levels.push(origLevel);
    return null;
  }
  this.setFocus(this.singletonFocus(row));
  var children = this.nextLevel();
  var newNode = children[origIndex];
  if (!newNode) {
    this.setFocus(origFocus);
    this.levels.push(origLevel);
    return null;
  }
  this.levels.push(children);
  return this.singletonFocus(children[origIndex]);
};

/**
 * Indicates if a virtual summary is possible.
 * @return {?sre.Focus}
 * @protected
 */
sre.TableWalker.prototype.jumpCell = function() {
  if (!this.isInTable_()) {
    return this.getFocus();
  }
  if (this.moved === sre.Walker.move.ROW) {
    this.moved = sre.Walker.move.CELL;
    var column = this.key - sre.EventUtil.KeyCode['0'];
    if (!this.isLegalJump_(this.row_, column)) {
      return this.getFocus();
    }
    // this.cell = [this.row, column];
    return this.jumpCell_(this.row_, column);
  }
  this.row_ = (this.key - sre.EventUtil.KeyCode['0']);
  this.moved = sre.Walker.move.ROW;
  return this.getFocus().clone();
};

// Basic idea:
// -- We know the cell position exists!
// -- Re-init the undo stack.
// -- Go up to the elibigle Table type.
// -- Pop foci off the levels.
// -- Push onto the undo stack.
// -- Go to cell position by pushing onto the levels.
/**
 * Jumps to the cell at the given row column position.
 * @param {number} row The row coordinate.
 * @param {number} column The column coordinate.
 * @return {sre.Focus} The newly focused cell.
 * @private
 */
sre.TableWalker.prototype.jumpCell_ = function(row, column) {
  // this.undoStack = new sre.Levels();
  // this.undoFocus = this.getFocus();
  var id = this.currentTable.id.toString();
  do {
    var level = this.levels.pop();
    // this.undoStack.push(level);
  } while (level.indexOf(id) === -1)
  this.levels.push(level);
  this.setFocus(this.singletonFocus(id));
  this.levels.push(this.nextLevel());
  var semRow = this.currentTable.childNodes[row - 1];
  this.setFocus(this.singletonFocus(semRow.id.toString()));
  this.levels.push(this.nextLevel());
  return this.singletonFocus(semRow.childNodes[column - 1].id.toString());
};

/**
 * Checks if a jump to a given row column position is possible in the current
 * table.
 * @param {number} row The row coordinate.
 * @param {number} column The column coordinate.
 * @return {boolean} True if the cell exists.
 * @private
 */
sre.TableWalker.prototype.isLegalJump_ = function(row, column) {
  var child = this.currentTable.childNodes[row - 1];
  return child && child.childNodes[column - 1];
};

/**
 * @return {boolean} True if we are inside a table.
 * @private
 */
sre.TableWalker.prototype.isInTable_ = function() {
  var snode = this.getFocus().getSemanticPrimary();
  while (snode) {
    if (sre.TableWalker.ELIGIBLE_TABLE_TYPES.indexOf(snode.type) !== -1) {
      this.currentTable = snode;
      return true;
    }
    snode = snode.parent;
  }
  return false;
};
<commit_msg>Code cleanup.<commit_after>// Copyright 2015 Volker Sorge
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview A table walker.
 *
 * @author volker.sorge@gmail.com (Volker Sorge)
 */

goog.provide('sre.TableWalker');

goog.require('sre.Focus');
goog.require('sre.Levels');
goog.require('sre.SyntaxWalker');
goog.require('sre.WalkerUtil');

/**
 * @constructor
 * @extends {sre.SyntaxWalker}
 * @override
 */
sre.TableWalker = function(node, generator, highlighter, xml) {
  sre.TableWalker.base(this, 'constructor', node, generator, highlighter, xml);

  /**
   * @type {boolean}
   */
  this.modifier = false;

  this.keyMapping[sre.EventUtil.KeyCode['0']] = goog.bind(this.jumpCell, this);
  this.keyMapping[sre.EventUtil.KeyCode['1']] = goog.bind(this.jumpCell, this);
  this.keyMapping[sre.EventUtil.KeyCode['2']] = goog.bind(this.jumpCell, this);
  this.keyMapping[sre.EventUtil.KeyCode['3']] = goog.bind(this.jumpCell, this);
  this.keyMapping[sre.EventUtil.KeyCode['4']] = goog.bind(this.jumpCell, this);
  this.keyMapping[sre.EventUtil.KeyCode['5']] = goog.bind(this.jumpCell, this);
  this.keyMapping[sre.EventUtil.KeyCode['6']] = goog.bind(this.jumpCell, this);
  this.keyMapping[sre.EventUtil.KeyCode['7']] = goog.bind(this.jumpCell, this);
  this.keyMapping[sre.EventUtil.KeyCode['8']] = goog.bind(this.jumpCell, this);
  this.keyMapping[sre.EventUtil.KeyCode['9']] = goog.bind(this.jumpCell, this);

  /**
   * @type {?sre.EventUtil.KeyCode}
   * @private
   */
  this.key_ = null;

  /**
   * @type {number}
   * @private
   */
  this.row_ = 0;

  /**
   * @type {?sre.SemanticNode}
   * @private
   */
  this.currentTable_ = null;

};
goog.inherits(sre.TableWalker, sre.SyntaxWalker);

/**
 * @override
 */
sre.TableWalker.prototype.move = function(key) {
  this.key_ = key;
  var result = sre.TableWalker.base(this, 'move', key);
  this.modifier = false;
  return result;
};

/**
 * @override
 */
sre.TableWalker.prototype.up = function() {
  this.moved = sre.Walker.move.UP;
  return this.eligibleCell_() ?
      this.verticalMove_(false) :
      sre.TableWalker.base(this, 'up');
};

/**
 * @override
 */
sre.TableWalker.prototype.down = function() {
  this.moved = sre.Walker.move.DOWN;
  return this.eligibleCell_() ?
      this.verticalMove_(true) :
      sre.TableWalker.base(this, 'down');
};

/**
 * @type {Array.<sre.SemanticAttr.Role>}
 */
sre.TableWalker.ELIGIBLE_CELL_ROLES = [
  sre.SemanticAttr.Role.DETERMINANT,
  sre.SemanticAttr.Role.ROWVECTOR,
  sre.SemanticAttr.Role.BINOMIAL,
  sre.SemanticAttr.Role.SQUAREMATRIX,
  sre.SemanticAttr.Role.MULTILINE,
  sre.SemanticAttr.Role.MATRIX,
  sre.SemanticAttr.Role.VECTOR,
  sre.SemanticAttr.Role.CASES,
  sre.SemanticAttr.Role.TABLE
];

/**
 * @type {Array.<sre.SemanticAttr.Type>}
 */
sre.TableWalker.ELIGIBLE_TABLE_TYPES = [
  sre.SemanticAttr.Type.MULTILINE,
  sre.SemanticAttr.Type.MATRIX,
  sre.SemanticAttr.Type.VECTOR,
  sre.SemanticAttr.Type.CASES,
  sre.SemanticAttr.Type.TABLE
];

/**
 * @return {boolean} True if the focused is an eligible table cell.
 * @private
 */
sre.TableWalker.prototype.eligibleCell_ = function() {
  var primary = this.getFocus().getSemanticPrimary();
  return this.modifier &&
        primary.type === sre.SemanticAttr.Type.CELL &&
    sre.TableWalker.ELIGIBLE_CELL_ROLES.indexOf(primary.role) !== -1;
};

/**
 * Performs a vertical move in a table.
 * @param {boolean} direction If true walk down, o/w up.
 * @return {?sre.Focus} The new focus.
 * @private
 */
sre.TableWalker.prototype.verticalMove_ = function(direction) {
  var parent = this.previousLevel();
  if (!parent) return null;
  var origFocus = this.getFocus();
  var origIndex = /** @type {number} */(
      this.levels.indexOf(this.primaryId()));
  var origLevel = this.levels.pop();
  var parentIndex = /** @type {number} */(
      this.levels.indexOf(parent));
  var row = /** @type {string} */(this.levels.get(
      direction ? parentIndex + 1 : parentIndex - 1));
  if (!row) {
    this.levels.push(origLevel);
    return null;
  }
  this.setFocus(this.singletonFocus(row));
  var children = this.nextLevel();
  var newNode = children[origIndex];
  if (!newNode) {
    this.setFocus(origFocus);
    this.levels.push(origLevel);
    return null;
  }
  this.levels.push(children);
  return this.singletonFocus(children[origIndex]);
};

/**
 * Indicates if a virtual summary is possible.
 * @return {?sre.Focus}
 * @protected
 */
sre.TableWalker.prototype.jumpCell = function() {
  if (!this.isInTable_()) {
    return this.getFocus();
  }
  if (this.moved === sre.Walker.move.ROW) {
    this.moved = sre.Walker.move.CELL;
    var column = this.key_ - sre.EventUtil.KeyCode['0'];
    if (!this.isLegalJump_(this.row_, column)) {
      return this.getFocus();
    }
    // this.cell = [this.row, column];
    return this.jumpCell_(this.row_, column);
  }
  this.row_ = (this.key_ - sre.EventUtil.KeyCode['0']);
  this.moved = sre.Walker.move.ROW;
  return this.getFocus().clone();
};

/**
 * Jumps to the cell at the given row column position.
 * @param {number} row The row coordinate.
 * @param {number} column The column coordinate.
 * @return {sre.Focus} The newly focused cell.
 * @private
 */
sre.TableWalker.prototype.jumpCell_ = function(row, column) {
  // We know the cell position exists!
  var id = this.currentTable_.id.toString();
  // Pop foci until we have reached the table.
  do {
    var level = this.levels.pop();
  } while (level.indexOf(id) === -1)
  // Go to cell position by pushing row and cell onto levels.
  this.levels.push(level);
  this.setFocus(this.singletonFocus(id));
  this.levels.push(this.nextLevel());
  var semRow = this.currentTable_.childNodes[row - 1];
  this.setFocus(this.singletonFocus(semRow.id.toString()));
  this.levels.push(this.nextLevel());
  return this.singletonFocus(semRow.childNodes[column - 1].id.toString());
};

/**
 * Checks if a jump to a given row column position is possible in the current
 * table.
 * @param {number} row The row coordinate.
 * @param {number} column The column coordinate.
 * @return {boolean} True if the cell exists.
 * @private
 */
sre.TableWalker.prototype.isLegalJump_ = function(row, column) {
  var child = this.currentTable_.childNodes[row - 1];
  return !!(child && child.childNodes[column - 1]);
};

/**
 * @return {boolean} True if we are inside a table.
 * @private
 */
sre.TableWalker.prototype.isInTable_ = function() {
  var snode = this.getFocus().getSemanticPrimary();
  while (snode) {
    if (sre.TableWalker.ELIGIBLE_TABLE_TYPES.indexOf(snode.type) !== -1) {
      this.currentTable_ = snode;
      return true;
    }
    snode = snode.parent;
  }
  return false;
};
<|endoftext|>


<commit_before>/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Famous Industries Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

'use strict';

/**
 * The Size class is responsible for processing Size from a node
 * @constructor Size
 */
function Size () {
    this._size = new Float32Array(3);
}

// an enumeration of the different types of size modes
Size.RELATIVE = 0;
Size.ABSOLUTE = 1;
Size.RENDER = 2;
Size.DEFAULT = Size.RELATIVE;

/**
 * fromSpecWithParent takes the parent node's size, the target node's spec,
 * and a target array to write to. Using the node's size mode it calculates
 * a final size for the node from the node's spec. Returns whether or not
 * the final size has changed from its last value.
 *
 * @param {Array} parentSize parent node's calculated size
 * @param {Node.Spec} node the target node's spec
 * @param {Array} target an array to write the result to
 *
 * @return {Boolean} true if the size of the node has changed.
 */
Size.prototype.fromSpecWithParent = function fromSpecWithParent (parentSize, node, target) {
    var spec = node.getValue().spec;
    var components = node.getComponents();
    var mode = spec.size.sizeMode;
    var prev;
    var changed = false;
    var len = components.length;
    var j;
    for (var i = 0 ; i < 3 ; i++) {
        switch (mode[i]) {
            case Size.RELATIVE:
                prev = target[i];
                target[i] = parentSize[i] * spec.size.proportional[i] + spec.size.differential[i];
                break;
            case Size.ABSOLUTE:
                prev = target[i];
                target[i] = spec.size.absolute[i];
                break;
            case Size.RENDER:
                var candidate;
                for (j = 0; j < len ; j++) {
                    if (components[j].getRenderSize) {
                        candidate = components[j].getRenderSize()[i];
                        prev = target[i];
                        target[i] = target[i] < candidate || target[i] === 0 ? candidate : target[i];
                    }
                }
                break;
        }
        changed = changed || prev !== target[i];
    }
    return changed;
};

module.exports = Size;
<commit_msg>Fix bug: components[j] can be null<commit_after>/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Famous Industries Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

'use strict';

/**
 * The Size class is responsible for processing Size from a node
 * @constructor Size
 */
function Size () {
    this._size = new Float32Array(3);
}

// an enumeration of the different types of size modes
Size.RELATIVE = 0;
Size.ABSOLUTE = 1;
Size.RENDER = 2;
Size.DEFAULT = Size.RELATIVE;

/**
 * fromSpecWithParent takes the parent node's size, the target node's spec,
 * and a target array to write to. Using the node's size mode it calculates
 * a final size for the node from the node's spec. Returns whether or not
 * the final size has changed from its last value.
 *
 * @param {Array} parentSize parent node's calculated size
 * @param {Node.Spec} node the target node's spec
 * @param {Array} target an array to write the result to
 *
 * @return {Boolean} true if the size of the node has changed.
 */
Size.prototype.fromSpecWithParent = function fromSpecWithParent (parentSize, node, target) {
    var spec = node.getValue().spec;
    var components = node.getComponents();
    var mode = spec.size.sizeMode;
    var prev;
    var changed = false;
    var len = components.length;
    var j;
    for (var i = 0 ; i < 3 ; i++) {
        switch (mode[i]) {
            case Size.RELATIVE:
                prev = target[i];
                target[i] = parentSize[i] * spec.size.proportional[i] + spec.size.differential[i];
                break;
            case Size.ABSOLUTE:
                prev = target[i];
                target[i] = spec.size.absolute[i];
                break;
            case Size.RENDER:
                var candidate;
                for (j = 0; j < len ; j++) {
                    if (components[j] && components[j].getRenderSize) {
                        candidate = components[j].getRenderSize()[i];
                        prev = target[i];
                        target[i] = target[i] < candidate || target[i] === 0 ? candidate : target[i];
                    }
                }
                break;
        }
        changed = changed || prev !== target[i];
    }
    return changed;
};

module.exports = Size;
<|endoftext|>