<commit_before>var moment = require("../../moment");

exports.format = {
    "format YY" : function(test) {
        test.expect(1);

        var b = moment(new Date(2009, 1, 14, 15, 25, 50, 125));
        test.equal(b.format('YY'), '09', 'YY ---> 09');
        test.done();
    },

    "format escape brackets" : function(test) {
        test.expect(7);

        var b = moment(new Date(2009, 1, 14, 15, 25, 50, 125));
        test.equal(b.format('[day]'), 'day', 'Single bracket');
        test.equal(b.format('[day] YY [YY]'), 'day 09 YY', 'Double bracket');
        test.equal(b.format('[YY'), '[09', 'Un-ended bracket');
        test.equal(b.format('[[YY]]'), '[YY]', 'Double nested brackets');
        test.equal(b.format('[[]'), '[', 'Escape open bracket');
        test.equal(b.format('[Last]'), 'Last', 'localized tokens');
        test.equal(b.format('[LLL]'), 'LLL', 'localized tokens');
        test.done();
    },

    "format milliseconds" : function(test) {
        test.expect(6);
        var b = moment(new Date(2009, 1, 14, 15, 25, 50, 123));
        test.equal(b.format('S'), '1', 'Deciseconds');
        test.equal(b.format('SS'), '12', 'Centiseconds');
        test.equal(b.format('SSS'), '123', 'Milliseconds');
        b.milliseconds(789);
        test.equal(b.format('S'), '7', 'Deciseconds');
        test.equal(b.format('SS'), '78', 'Centiseconds');
        test.equal(b.format('SSS'), '789', 'Milliseconds');
        test.done();
    },

    "format timezone" : function(test) {
        test.expect(2);

        var b = moment(new Date(2010, 1, 14, 15, 25, 50, 125));
        var explanation = 'moment().format("z") = ' + b.format('z') + ' It should be something like "PST"'
        if (moment().zone() === -60) {
            explanation += "For UTC+1 this is a known issue, see https://github.com/timrwood/moment/issues/162";
        }
        test.ok(b.format('Z').match(/^[\+\-]\d\d:\d\d$/), b.format('Z') + ' should be something like "+07:30"');
        test.ok(b.format('ZZ').match(/^[\+\-]\d{4}$/), b.format('ZZ') + ' should be something like "+0700"');
        test.done();
    },

    "format multiple with zone" : function(test) {
        test.expect(1);

        var b = moment('2012-10-08 -1200', ['YYYY ZZ', 'YYYY-MM-DD ZZ']);
        test.equals(b.format('YYYY-MM'), '2012-10', 'Parsing multiple formats should not crash with different sized formats');
        test.done();
    },

    "isDST" : function(test) {
        test.expect(2);

        var janOffset = new Date(2011, 0, 1).getTimezoneOffset(),
            julOffset = new Date(2011, 6, 1).getTimezoneOffset(),
            janIsDst = janOffset < julOffset,
            julIsDst = julOffset < janOffset,
            jan1 = moment([2011]),
            jul1 = moment([2011, 6]);

        if (janIsDst && julIsDst) {
            test.ok(0, 'January and July cannot both be in DST');
            test.ok(0, 'January and July cannot both be in DST');
        } else if (janIsDst) {
            test.ok(jan1.isDST(), 'January 1 is DST');
            test.ok(!jul1.isDST(), 'July 1 is not DST');
        } else if (julIsDst) {
            test.ok(!jan1.isDST(), 'January 1 is not DST');
            test.ok(jul1.isDST(), 'July 1 is DST');
        } else {
            test.ok(!jan1.isDST(), 'January 1 is not DST');
            test.ok(!jul1.isDST(), 'July 1 is not DST');
        }
        test.done();
    },

    "zone" : function(test) {
        test.expect(3);

        if (moment().zone() > 0) {
            test.ok(moment().format('ZZ').indexOf('-') > -1, 'When the zone() offset is greater than 0, the ISO offset should be less than zero');
        }
        if (moment().zone() < 0) {
            test.ok(moment().format('ZZ').indexOf('+') > -1, 'When the zone() offset is less than 0, the ISO offset should be greater than zero');
        }
        if (moment().zone() == 0) {
            test.ok(moment().format('ZZ').indexOf('+') > -1, 'When the zone() offset is equal to 0, the ISO offset should be positive zero');
        }
        if (moment().zone() === 0) {
           test.equal(moment().zone(), 0, 'moment.fn.zone should be a multiple of 15 (was ' + moment().zone() + ')');
        } else {
           test.equal(moment().zone() % 15, 0, 'moment.fn.zone should be a multiple of 15 (was ' + moment().zone() + ')');
        }
        test.equal(moment().zone(), new Date().getTimezoneOffset(), 'zone should equal getTimezoneOffset');
        test.done();
    },

    "default format" : function(test) {
        test.expect(1);
        var isoRegex = /\d{4}.\d\d.\d\dT\d\d.\d\d.\d\d[\+\-]\d\d:\d\d/;
        test.ok(isoRegex.exec(moment().format()), "default format (" + moment().format() + ") should match ISO");
        test.done();
    }
};
<commit_msg>more comprehensive tests for #380<commit_after>var moment = require("../../moment");

exports.format = {
    "format YY" : function(test) {
        test.expect(1);

        var b = moment(new Date(2009, 1, 14, 15, 25, 50, 125));
        test.equal(b.format('YY'), '09', 'YY ---> 09');
        test.done();
    },

    "format escape brackets" : function(test) {
        test.expect(7);

        var b = moment(new Date(2009, 1, 14, 15, 25, 50, 125));
        test.equal(b.format('[day]'), 'day', 'Single bracket');
        test.equal(b.format('[day] YY [YY]'), 'day 09 YY', 'Double bracket');
        test.equal(b.format('[YY'), '[09', 'Un-ended bracket');
        test.equal(b.format('[[YY]]'), '[YY]', 'Double nested brackets');
        test.equal(b.format('[[]'), '[', 'Escape open bracket');
        test.equal(b.format('[Last]'), 'Last', 'localized tokens');
        test.equal(b.format('[L] L'), 'L 02/14/2009', 'localized tokens with escaped localized tokens');
        test.done();
    },

    "format milliseconds" : function(test) {
        test.expect(6);
        var b = moment(new Date(2009, 1, 14, 15, 25, 50, 123));
        test.equal(b.format('S'), '1', 'Deciseconds');
        test.equal(b.format('SS'), '12', 'Centiseconds');
        test.equal(b.format('SSS'), '123', 'Milliseconds');
        b.milliseconds(789);
        test.equal(b.format('S'), '7', 'Deciseconds');
        test.equal(b.format('SS'), '78', 'Centiseconds');
        test.equal(b.format('SSS'), '789', 'Milliseconds');
        test.done();
    },

    "format timezone" : function(test) {
        test.expect(2);

        var b = moment(new Date(2010, 1, 14, 15, 25, 50, 125));
        var explanation = 'moment().format("z") = ' + b.format('z') + ' It should be something like "PST"'
        if (moment().zone() === -60) {
            explanation += "For UTC+1 this is a known issue, see https://github.com/timrwood/moment/issues/162";
        }
        test.ok(b.format('Z').match(/^[\+\-]\d\d:\d\d$/), b.format('Z') + ' should be something like "+07:30"');
        test.ok(b.format('ZZ').match(/^[\+\-]\d{4}$/), b.format('ZZ') + ' should be something like "+0700"');
        test.done();
    },

    "format multiple with zone" : function(test) {
        test.expect(1);

        var b = moment('2012-10-08 -1200', ['YYYY ZZ', 'YYYY-MM-DD ZZ']);
        test.equals(b.format('YYYY-MM'), '2012-10', 'Parsing multiple formats should not crash with different sized formats');
        test.done();
    },

    "isDST" : function(test) {
        test.expect(2);

        var janOffset = new Date(2011, 0, 1).getTimezoneOffset(),
            julOffset = new Date(2011, 6, 1).getTimezoneOffset(),
            janIsDst = janOffset < julOffset,
            julIsDst = julOffset < janOffset,
            jan1 = moment([2011]),
            jul1 = moment([2011, 6]);

        if (janIsDst && julIsDst) {
            test.ok(0, 'January and July cannot both be in DST');
            test.ok(0, 'January and July cannot both be in DST');
        } else if (janIsDst) {
            test.ok(jan1.isDST(), 'January 1 is DST');
            test.ok(!jul1.isDST(), 'July 1 is not DST');
        } else if (julIsDst) {
            test.ok(!jan1.isDST(), 'January 1 is not DST');
            test.ok(jul1.isDST(), 'July 1 is DST');
        } else {
            test.ok(!jan1.isDST(), 'January 1 is not DST');
            test.ok(!jul1.isDST(), 'July 1 is not DST');
        }
        test.done();
    },

    "zone" : function(test) {
        test.expect(3);

        if (moment().zone() > 0) {
            test.ok(moment().format('ZZ').indexOf('-') > -1, 'When the zone() offset is greater than 0, the ISO offset should be less than zero');
        }
        if (moment().zone() < 0) {
            test.ok(moment().format('ZZ').indexOf('+') > -1, 'When the zone() offset is less than 0, the ISO offset should be greater than zero');
        }
        if (moment().zone() == 0) {
            test.ok(moment().format('ZZ').indexOf('+') > -1, 'When the zone() offset is equal to 0, the ISO offset should be positive zero');
        }
        if (moment().zone() === 0) {
           test.equal(moment().zone(), 0, 'moment.fn.zone should be a multiple of 15 (was ' + moment().zone() + ')');
        } else {
           test.equal(moment().zone() % 15, 0, 'moment.fn.zone should be a multiple of 15 (was ' + moment().zone() + ')');
        }
        test.equal(moment().zone(), new Date().getTimezoneOffset(), 'zone should equal getTimezoneOffset');
        test.done();
    },

    "default format" : function(test) {
        test.expect(1);
        var isoRegex = /\d{4}.\d\d.\d\dT\d\d.\d\d.\d\d[\+\-]\d\d:\d\d/;
        test.ok(isoRegex.exec(moment().format()), "default format (" + moment().format() + ") should match ISO");
        test.done();
    }
};
<|endoftext|>


<commit_before>import {takeLatest, takeEvery} from 'redux-saga';
import {call, put, select, fork} from 'redux-saga/effects';
import {loadFollows, fetchFollowCount} from 'app/redux/FollowSaga';
import {getContent} from 'app/redux/SagaShared';
import Apis from 'shared/api_client/ApiInstances';
import GlobalReducer from './GlobalReducer';
import constants from './constants';
import {fromJS, Map} from 'immutable'

export const fetchDataWatches = [watchLocationChange, watchDataRequests, watchApiRequests, watchFetchJsonRequests, watchFetchState, watchGetContent];

export function* watchDataRequests() {
    yield* takeLatest('REQUEST_DATA', fetchData);
}

export function* watchGetContent() {
    yield* takeEvery('GET_CONTENT', getContentCaller);
}

export function* getContentCaller(action) {
    yield getContent(action.payload);
}

let is_initial_state = true;
export function* fetchState(location_change_action) {
    const {pathname} = location_change_action.payload;
    const m = pathname.match(/^\/@([a-z0-9\.-]+)/)
    if(m && m.length === 2) {
        const username = m[1]
        yield fork(fetchFollowCount, username)
        yield fork(loadFollows, "get_followers", username, 'blog')
        yield fork(loadFollows, "get_following", username, 'blog')
    }

    // `ignore_fetch` case should only trigger on initial page load. No need to call
    // fetchState immediately after loading fresh state from the server. Details: #593
    const server_location = yield select(state => state.offchain.get('server_location'));
    const ignore_fetch = (pathname === server_location && is_initial_state)
    is_initial_state = false;
    if(ignore_fetch) return;

    let url = `${pathname}`;
    if (url === '/') url = 'trending';
    // Replace /curation-rewards and /author-rewards with /transfers for UserProfile
    // to resolve data correctly
    if (url.indexOf("/curation-rewards") !== -1) url = url.replace("/curation-rewards", "/transfers");
    if (url.indexOf("/author-rewards") !== -1) url = url.replace("/author-rewards", "/transfers");

    try {
        const db_api = Apis.instance().db_api;
        const state = yield call([db_api, db_api.exec], 'get_state', [url]);
        yield put(GlobalReducer.actions.receiveState(state));
    } catch (error) {
        console.error('~~ Saga fetchState error ~~>', url, error);
        yield put({type: 'global/STEEM_API_ERROR', error: error.message});
    }
}

export function* watchLocationChange() {
    yield* takeLatest('@@router/LOCATION_CHANGE', fetchState);
}

export function* watchFetchState() {
    yield* takeLatest('FETCH_STATE', fetchState);
}

export function* fetchData(action) {
    const {order, author, permlink, accountname} = action.payload;
    let {category} = action.payload;
    if( !category ) category = "";
    category = category.toLowerCase();

    yield put({type: 'global/FETCHING_DATA', payload: {order, category}});
    let call_name, args;
    if (order === 'trending') {
        call_name = 'get_discussions_by_trending';
        args = [
        { tag: category,
          limit: constants.FETCH_DATA_BATCH_SIZE,
          start_author: author,
          start_permlink: permlink}];
    } else if (order === 'trending30') {
        call_name = 'get_discussions_by_trending30';
        args = [
        { tag: category,
          limit: constants.FETCH_DATA_BATCH_SIZE,
          start_author: author,
          start_permlink: permlink}];
    } else if (order === 'promoted') {
        call_name = 'get_discussions_by_promoted';
        args = [
        { tag: category,
          limit: constants.FETCH_DATA_BATCH_SIZE,
          start_author: author,
          start_permlink: permlink}];
    } else if( order === 'active' ) {
        call_name = 'get_discussions_by_active';
        args = [
        { tag: category,
          limit: constants.FETCH_DATA_BATCH_SIZE,
          start_author: author,
          start_permlink: permlink}];
    } else if( order === 'cashout' ) {
        call_name = 'get_discussions_by_cashout';
        args = [
        { tag: category,
          limit: constants.FETCH_DATA_BATCH_SIZE,
          start_author: author,
          start_permlink: permlink}];
    } else if( order === 'updated' ) {
        call_name = 'get_discussions_by_active';
        args = [
        { tag: category,
          limit: constants.FETCH_DATA_BATCH_SIZE,
          start_author: author,
          start_permlink: permlink}];
    } else if( order === 'created' || order === 'recent' ) {
        call_name = 'get_discussions_by_created';
        args = [
        { tag: category,
          limit: constants.FETCH_DATA_BATCH_SIZE,
          start_author: author,
          start_permlink: permlink}];
    } else if( order === 'by_replies' ) {
        call_name = 'get_replies_by_last_update';
        args = [author, permlink, constants.FETCH_DATA_BATCH_SIZE];
    } else if( order === 'responses' ) {
        call_name = 'get_discussions_by_children';
        args = [
        { tag: category,
          limit: constants.FETCH_DATA_BATCH_SIZE,
          start_author: author,
          start_permlink: permlink}];
    } else if( order === 'votes' ) {
        call_name = 'get_discussions_by_votes';
        args = [
        { tag: category,
          limit: constants.FETCH_DATA_BATCH_SIZE,
          start_author: author,
          start_permlink: permlink}];
    } else if( order === 'hot' ) {
        call_name = 'get_discussions_by_hot';
        args = [
        { tag: category,
          limit: constants.FETCH_DATA_BATCH_SIZE,
          start_author: author,
          start_permlink: permlink}];
    } else if( order === 'by_feed' ) { // https://github.com/steemit/steem/issues/249
        call_name = 'get_discussions_by_feed';
        args = [
        { tag: accountname,
          limit: constants.FETCH_DATA_BATCH_SIZE,
          start_author: author,
          start_permlink: permlink}];
    } else if( order === 'by_author' ) {
        call_name = 'get_discussions_by_blog';
        args = [
        { tag: accountname,
          limit: constants.FETCH_DATA_BATCH_SIZE,
          start_author: author,
          start_permlink: permlink}];
    } else if( order === 'by_comments' ) {
        call_name = 'get_discussions_by_comments';
        args = [
        { limit: constants.FETCH_DATA_BATCH_SIZE,
          start_author: author,
          start_permlink: permlink}];
    } else {
        call_name = 'get_discussions_by_active';
        args = [{
            tag: category,
            limit: constants.FETCH_DATA_BATCH_SIZE,
            start_author: author,
            start_permlink: permlink}];
    }
    try {
        const db_api = Apis.instance().db_api;
        const data = yield call([db_api, db_api.exec], call_name, args);
        yield put(GlobalReducer.actions.receiveData({data, order, category, author, permlink, accountname}));
    } catch (error) {
        console.error('~~ Saga fetchData error ~~>', call_name, args, error);
        yield put({type: 'global/STEEM_API_ERROR', error: error.message});
    }
}

export function* watchApiRequests() {
    yield* takeEvery('global/FETCH_API', fetchApi);
}
export function* fetchApi({payload: {exec, key, reducer, skipLoading = false}}) {
    const [api, method, ...args] = exec
    try {
        const apiInst = Apis.instance()[api];
        yield put(GlobalReducer.actions.update({key, notSet: Map(),
            updater: m => m.mergeDeep({loading: true})
        }))
        const value = yield skipLoading ? apiInst.exec(method, args) :
            call([apiInst, apiInst.exec], method, args)
        let v = fromJS(value)
        if(reducer) v = v.reduce(...reducer)
        yield put(GlobalReducer.actions.update({key, notSet: Map(),
            updater: m => m.mergeDeep({result: v, error: null, loading: false})
        }))
    } catch (error) {
        console.error('~~ Saga fetchApi error ~~>', method, args, error);
        yield put(GlobalReducer.actions.set({key, value: {error, result: undefined, loading: false}}))
    }
}

// export function* watchMetaRequests() {
//     yield* takeLatest('global/REQUEST_META', fetchMeta);
// }
export function* fetchMeta({payload: {id, link}}) {
    try {
        const metaArray = yield call(() => new Promise((resolve, reject) => {
            function reqListener() {
                const resp = JSON.parse(this.responseText)
                if (resp.error) {
                    reject(resp.error)
                    return
                }
                resolve(resp)
            }
            const oReq = new XMLHttpRequest()
            oReq.addEventListener('load', reqListener)
            oReq.open('GET', '/http_metadata/' + link)
            oReq.send()
        }))
        const {title, metaTags} = metaArray
        let meta = {title}
        for (let i = 0; i < metaTags.length; i++) {
            const [name, content] = metaTags[i]
            meta[name] = content
        }
        // http://postimg.org/image/kbefrpbe9/
        meta = {
            link,
            card: meta['twitter:card'],
            site: meta['twitter:site'], // @username tribbute
            title: meta['twitter:title'],
            description: meta['twitter:description'],
            image: meta['twitter:image'],
            alt: meta['twitter:alt'],
        }
        if(!meta.image) {
            meta.image = meta['twitter:image:src']
        }
        yield put(GlobalReducer.actions.receiveMeta({id, meta}))
    } catch(error) {
        yield put(GlobalReducer.actions.receiveMeta({id, meta: {error}}))
    }
}

export function* watchFetchJsonRequests() {
    yield* takeEvery('global/FETCH_JSON', fetchJson);
}

/**
    @arg {string} id unique key for result global['fetchJson_' + id]
    @arg {string} url
    @arg {object} body (for JSON.stringify)
*/
function* fetchJson({payload: {id, url, body, successCallback, skipLoading = false}}) {
    try {
        const payload = {
            method: body ? 'POST' : 'GET',
            headers: {
                Accept: 'application/json',
                'Content-Type': 'application/json'
            },
            body: body ? JSON.stringify(body) : undefined
        }
        let result = yield skipLoading ? fetch(url, payload) : call(fetch, url, payload)
        result = yield result.json()
        if(successCallback) result = successCallback(result)
        yield put(GlobalReducer.actions.fetchJsonResult({id, result}))
    } catch(error) {
        console.error('fetchJson', error)
        yield put(GlobalReducer.actions.fetchJsonResult({id, error}))
    }
}
<commit_msg>Replace primary get_state call with steem-js. #1119<commit_after>import {takeLatest, takeEvery} from 'redux-saga';
import {call, put, select, fork} from 'redux-saga/effects';
import {loadFollows, fetchFollowCount} from 'app/redux/FollowSaga';
import {getContent} from 'app/redux/SagaShared';
import Apis from 'shared/api_client/ApiInstances';
import GlobalReducer from './GlobalReducer';
import constants from './constants';
import {fromJS, Map} from 'immutable'
import {api} from 'steem';

export const fetchDataWatches = [watchLocationChange, watchDataRequests, watchApiRequests, watchFetchJsonRequests, watchFetchState, watchGetContent];

export function* watchDataRequests() {
    yield* takeLatest('REQUEST_DATA', fetchData);
}

export function* watchGetContent() {
    yield* takeEvery('GET_CONTENT', getContentCaller);
}

export function* getContentCaller(action) {
    yield getContent(action.payload);
}

let is_initial_state = true;
export function* fetchState(location_change_action) {
    const {pathname} = location_change_action.payload;
    const m = pathname.match(/^\/@([a-z0-9\.-]+)/)
    if(m && m.length === 2) {
        const username = m[1]
        yield fork(fetchFollowCount, username)
        yield fork(loadFollows, "get_followers", username, 'blog')
        yield fork(loadFollows, "get_following", username, 'blog')
    }

    // `ignore_fetch` case should only trigger on initial page load. No need to call
    // fetchState immediately after loading fresh state from the server. Details: #593
    const server_location = yield select(state => state.offchain.get('server_location'));
    const ignore_fetch = (pathname === server_location && is_initial_state)
    is_initial_state = false;
    if(ignore_fetch) return;

    let url = `${pathname}`;
    if (url === '/') url = 'trending';
    // Replace /curation-rewards and /author-rewards with /transfers for UserProfile
    // to resolve data correctly
    if (url.indexOf("/curation-rewards") !== -1) url = url.replace("/curation-rewards", "/transfers");
    if (url.indexOf("/author-rewards") !== -1) url = url.replace("/author-rewards", "/transfers");

    try {
        const state = yield call([api, api.getStateAsync], url)
        yield put(GlobalReducer.actions.receiveState(state));
    } catch (error) {
        console.error('~~ Saga fetchState error ~~>', url, error);
        yield put({type: 'global/STEEM_API_ERROR', error: error.message});
    }
}

export function* watchLocationChange() {
    yield* takeLatest('@@router/LOCATION_CHANGE', fetchState);
}

export function* watchFetchState() {
    yield* takeLatest('FETCH_STATE', fetchState);
}

export function* fetchData(action) {
    const {order, author, permlink, accountname} = action.payload;
    let {category} = action.payload;
    if( !category ) category = "";
    category = category.toLowerCase();

    yield put({type: 'global/FETCHING_DATA', payload: {order, category}});
    let call_name, args;
    if (order === 'trending') {
        call_name = 'get_discussions_by_trending';
        args = [
        { tag: category,
          limit: constants.FETCH_DATA_BATCH_SIZE,
          start_author: author,
          start_permlink: permlink}];
    } else if (order === 'trending30') {
        call_name = 'get_discussions_by_trending30';
        args = [
        { tag: category,
          limit: constants.FETCH_DATA_BATCH_SIZE,
          start_author: author,
          start_permlink: permlink}];
    } else if (order === 'promoted') {
        call_name = 'get_discussions_by_promoted';
        args = [
        { tag: category,
          limit: constants.FETCH_DATA_BATCH_SIZE,
          start_author: author,
          start_permlink: permlink}];
    } else if( order === 'active' ) {
        call_name = 'get_discussions_by_active';
        args = [
        { tag: category,
          limit: constants.FETCH_DATA_BATCH_SIZE,
          start_author: author,
          start_permlink: permlink}];
    } else if( order === 'cashout' ) {
        call_name = 'get_discussions_by_cashout';
        args = [
        { tag: category,
          limit: constants.FETCH_DATA_BATCH_SIZE,
          start_author: author,
          start_permlink: permlink}];
    } else if( order === 'updated' ) {
        call_name = 'get_discussions_by_active';
        args = [
        { tag: category,
          limit: constants.FETCH_DATA_BATCH_SIZE,
          start_author: author,
          start_permlink: permlink}];
    } else if( order === 'created' || order === 'recent' ) {
        call_name = 'get_discussions_by_created';
        args = [
        { tag: category,
          limit: constants.FETCH_DATA_BATCH_SIZE,
          start_author: author,
          start_permlink: permlink}];
    } else if( order === 'by_replies' ) {
        call_name = 'get_replies_by_last_update';
        args = [author, permlink, constants.FETCH_DATA_BATCH_SIZE];
    } else if( order === 'responses' ) {
        call_name = 'get_discussions_by_children';
        args = [
        { tag: category,
          limit: constants.FETCH_DATA_BATCH_SIZE,
          start_author: author,
          start_permlink: permlink}];
    } else if( order === 'votes' ) {
        call_name = 'get_discussions_by_votes';
        args = [
        { tag: category,
          limit: constants.FETCH_DATA_BATCH_SIZE,
          start_author: author,
          start_permlink: permlink}];
    } else if( order === 'hot' ) {
        call_name = 'get_discussions_by_hot';
        args = [
        { tag: category,
          limit: constants.FETCH_DATA_BATCH_SIZE,
          start_author: author,
          start_permlink: permlink}];
    } else if( order === 'by_feed' ) { // https://github.com/steemit/steem/issues/249
        call_name = 'get_discussions_by_feed';
        args = [
        { tag: accountname,
          limit: constants.FETCH_DATA_BATCH_SIZE,
          start_author: author,
          start_permlink: permlink}];
    } else if( order === 'by_author' ) {
        call_name = 'get_discussions_by_blog';
        args = [
        { tag: accountname,
          limit: constants.FETCH_DATA_BATCH_SIZE,
          start_author: author,
          start_permlink: permlink}];
    } else if( order === 'by_comments' ) {
        call_name = 'get_discussions_by_comments';
        args = [
        { limit: constants.FETCH_DATA_BATCH_SIZE,
          start_author: author,
          start_permlink: permlink}];
    } else {
        call_name = 'get_discussions_by_active';
        args = [{
            tag: category,
            limit: constants.FETCH_DATA_BATCH_SIZE,
            start_author: author,
            start_permlink: permlink}];
    }
    try {
        const db_api = Apis.instance().db_api;
        const data = yield call([db_api, db_api.exec], call_name, args);
        yield put(GlobalReducer.actions.receiveData({data, order, category, author, permlink, accountname}));
    } catch (error) {
        console.error('~~ Saga fetchData error ~~>', call_name, args, error);
        yield put({type: 'global/STEEM_API_ERROR', error: error.message});
    }
}

export function* watchApiRequests() {
    yield* takeEvery('global/FETCH_API', fetchApi);
}
export function* fetchApi({payload: {exec, key, reducer, skipLoading = false}}) {
    const [api, method, ...args] = exec
    try {
        const apiInst = Apis.instance()[api];
        yield put(GlobalReducer.actions.update({key, notSet: Map(),
            updater: m => m.mergeDeep({loading: true})
        }))
        const value = yield skipLoading ? apiInst.exec(method, args) :
            call([apiInst, apiInst.exec], method, args)
        let v = fromJS(value)
        if(reducer) v = v.reduce(...reducer)
        yield put(GlobalReducer.actions.update({key, notSet: Map(),
            updater: m => m.mergeDeep({result: v, error: null, loading: false})
        }))
    } catch (error) {
        console.error('~~ Saga fetchApi error ~~>', method, args, error);
        yield put(GlobalReducer.actions.set({key, value: {error, result: undefined, loading: false}}))
    }
}

// export function* watchMetaRequests() {
//     yield* takeLatest('global/REQUEST_META', fetchMeta);
// }
export function* fetchMeta({payload: {id, link}}) {
    try {
        const metaArray = yield call(() => new Promise((resolve, reject) => {
            function reqListener() {
                const resp = JSON.parse(this.responseText)
                if (resp.error) {
                    reject(resp.error)
                    return
                }
                resolve(resp)
            }
            const oReq = new XMLHttpRequest()
            oReq.addEventListener('load', reqListener)
            oReq.open('GET', '/http_metadata/' + link)
            oReq.send()
        }))
        const {title, metaTags} = metaArray
        let meta = {title}
        for (let i = 0; i < metaTags.length; i++) {
            const [name, content] = metaTags[i]
            meta[name] = content
        }
        // http://postimg.org/image/kbefrpbe9/
        meta = {
            link,
            card: meta['twitter:card'],
            site: meta['twitter:site'], // @username tribbute
            title: meta['twitter:title'],
            description: meta['twitter:description'],
            image: meta['twitter:image'],
            alt: meta['twitter:alt'],
        }
        if(!meta.image) {
            meta.image = meta['twitter:image:src']
        }
        yield put(GlobalReducer.actions.receiveMeta({id, meta}))
    } catch(error) {
        yield put(GlobalReducer.actions.receiveMeta({id, meta: {error}}))
    }
}

export function* watchFetchJsonRequests() {
    yield* takeEvery('global/FETCH_JSON', fetchJson);
}

/**
    @arg {string} id unique key for result global['fetchJson_' + id]
    @arg {string} url
    @arg {object} body (for JSON.stringify)
*/
function* fetchJson({payload: {id, url, body, successCallback, skipLoading = false}}) {
    try {
        const payload = {
            method: body ? 'POST' : 'GET',
            headers: {
                Accept: 'application/json',
                'Content-Type': 'application/json'
            },
            body: body ? JSON.stringify(body) : undefined
        }
        let result = yield skipLoading ? fetch(url, payload) : call(fetch, url, payload)
        result = yield result.json()
        if(successCallback) result = successCallback(result)
        yield put(GlobalReducer.actions.fetchJsonResult({id, result}))
    } catch(error) {
        console.error('fetchJson', error)
        yield put(GlobalReducer.actions.fetchJsonResult({id, error}))
    }
}
<|endoftext|>


<commit_before>describe('Montar objeto pdfmake', function () {
    var parseHtml;

    beforeEach(function(){
      parseHtml = new ParseHtml();
    });

    it('parse link', function () {
        var html = '
TítuloLei nº 6.766, de 19 de Dezembro de 1979
';
        var content = [];
        var result = [
            { 'stack': [
                { 'text': [] },
                {'stack': [
                    { 'text': [
                        { 'text': 'TítuloLei nº 6.766, de 19 de Dezembro de 1979' }
                    ]}
                ]}
            ]}
        ];

        parseHtml.parseHtml(content, html);

        expect(content).toEqual(result);
    });

    it('parse span', function () {
        var html = '
Test
';
        var content = [];
        var result = [{
            stack: [{ 'text': [{ text: 'Test' }] }]
        }];

        parseHtml.parseHtml(content, html);

        expect(content).toEqual(result);
    });

    it('parse bold', function () {
        var html = '
Test
';
        var content = [];
        var result = [{
            stack: [{ 'text': [{ text: 'Test', bold: true }] }]
        }];

        parseHtml.parseHtml(content, html);

        expect(content).toEqual(result);
    });

    it('parse underline', function () {
        var html = '
Test
';
        var content = [];
        var result = [{ stack: [{ text: [{ text: 'Test', decoration: 'underline' }] }] }];

        parseHtml.parseHtml(content, html);

        expect(content).toEqual(result);
    });

    it('parse italic', function () {
        var html = '
Test
';
        var content = [];
        var result = [{ stack: [{ text: [{ text: 'Test', italics: true }] }] }];

        parseHtml.parseHtml(content, html);

        expect(content).toEqual(result);
    });
});
<commit_msg>Adicionando teste para tabela<commit_after>describe('Montar objeto pdfmake', function () {
    var parseHtml;

    beforeEach(function(){
      parseHtml = new ParseHtml();
    });

    it('parse link', function () {
        var html = '
TítuloLei nº 6.766, de 19 de Dezembro de 1979
';
        var content = [];
        var result = [
            { 'stack': [
                { 'text': [] },
                {'stack': [
                    { 'text': [
                        { 'text': 'TítuloLei nº 6.766, de 19 de Dezembro de 1979' }
                    ]}
                ]}
            ]}
        ];

        parseHtml.parseHtml(content, html);

        expect(content).toEqual(result);
    });

    it('parse span', function () {
        var html = '
Test
';
        var content = [];
        var result = [{
            stack: [{ 'text': [{ text: 'Test' }] }]
        }];

        parseHtml.parseHtml(content, html);

        expect(content).toEqual(result);
    });

    it('parse bold', function () {
        var html = '
Test
';
        var content = [];
        var result = [{
            stack: [{ 'text': [{ text: 'Test', bold: true }] }]
        }];

        parseHtml.parseHtml(content, html);

        expect(content).toEqual(result);
    });

    it('parse underline', function () {
        var html = '
Test
';
        var content = [];
        var result = [{ stack: [{ text: [{ text: 'Test', decoration: 'underline' }] }] }];

        parseHtml.parseHtml(content, html);

        expect(content).toEqual(result);
    });

    it('parse italic', function () {
        var html = '
Test
';
        var content = [];
        var result = [{ stack: [{ text: [{ text: 'Test', italics: true }] }] }];

        parseHtml.parseHtml(content, html);

        expect(content).toEqual(result);
    });

    it('parse table', function () {
        var html = '

Test

';
        var content = [];
        var result = [{ table: { widths: [ '*' ],
            body: [[ { stack: [ { text: [ { text: 'Test' } ] }] }] ] },
            layout: 'noBorders'
        }];

        parseHtml.parseHtml(content, html);

        expect(content).toEqual(result);
    });
});
<|endoftext|>


<commit_before>exports.config = {
  sauceUser: process.env.SAUCE_USERNAME,
  sauceKey: process.env.SAUCE_ACCESS_KEY,

  multiCapabilities: [{
        name: 'FireFox on XP',
        browserName: 'firefox',
        version: '19',
        platform: 'XP',
        build: process.env.TRAVIS_BUILD_NUMBER,
        'tunnel-identifier': process.env.TRAVIS_JOB_NUMBER
    }, {
        name: 'Chrome on XP',
        browserName: 'chrome',
        platform: 'XP',
        build: process.env.TRAVIS_BUILD_NUMBER,
        'tunnel-identifier': process.env.TRAVIS_JOB_NUMBER
    }, {
        name: 'Chrome on Linux',
        browserName: 'chrome',
        platform: 'linux',
        build: process.env.TRAVIS_BUILD_NUMBER,
        'tunnel-identifier': process.env.TRAVIS_JOB_NUMBER
    }, {
        name: 'IE10 on Windows 8',
        browserName: 'internet explorer',
        platform: 'WIN8',
        version: '10',
        build: process.env.TRAVIS_BUILD_NUMBER,
        'tunnel-identifier': process.env.TRAVIS_JOB_NUMBER
    }, {
        name: 'IE9 on Visa',
        browserName: 'internet explorer',
        platform: 'VISTA',
        version: '9',
        build: process.env.TRAVIS_BUILD_NUMBER,
        'tunnel-identifier': process.env.TRAVIS_JOB_NUMBER
    }, {
        name 'IE8 on XP',
        browserName: 'internet explorer',
        platform: 'XP',
        version: '8',
        build: process.env.TRAVIS_BUILD_NUMBER,
        'tunnel-identifier': process.env.TRAVIS_JOB_NUMBER
    }],

  baseUrl: 'http://localhost:8080',

  specs: ['*_test.js'],

  framework: 'mocha',

  mochaOpts: {
    reporter: 'spec',
    slow: 3000
  }
};<commit_msg>Fixed typo in saucelabs test config<commit_after>exports.config = {
  sauceUser: process.env.SAUCE_USERNAME,
  sauceKey: process.env.SAUCE_ACCESS_KEY,

  multiCapabilities: [{
        name: 'FireFox on XP',
        browserName: 'firefox',
        version: '19',
        platform: 'XP',
        build: process.env.TRAVIS_BUILD_NUMBER,
        'tunnel-identifier': process.env.TRAVIS_JOB_NUMBER
    }, {
        name: 'Chrome on XP',
        browserName: 'chrome',
        platform: 'XP',
        build: process.env.TRAVIS_BUILD_NUMBER,
        'tunnel-identifier': process.env.TRAVIS_JOB_NUMBER
    }, {
        name: 'Chrome on Linux',
        browserName: 'chrome',
        platform: 'linux',
        build: process.env.TRAVIS_BUILD_NUMBER,
        'tunnel-identifier': process.env.TRAVIS_JOB_NUMBER
    }, {
        name: 'IE10 on Windows 8',
        browserName: 'internet explorer',
        platform: 'WIN8',
        version: '10',
        build: process.env.TRAVIS_BUILD_NUMBER,
        'tunnel-identifier': process.env.TRAVIS_JOB_NUMBER
    }, {
        name: 'IE9 on Visa',
        browserName: 'internet explorer',
        platform: 'VISTA',
        version: '9',
        build: process.env.TRAVIS_BUILD_NUMBER,
        'tunnel-identifier': process.env.TRAVIS_JOB_NUMBER
    }, {
        name: 'IE8 on XP',
        browserName: 'internet explorer',
        platform: 'XP',
        version: '8',
        build: process.env.TRAVIS_BUILD_NUMBER,
        'tunnel-identifier': process.env.TRAVIS_JOB_NUMBER
    }],

  baseUrl: 'http://localhost:8080',

  specs: ['*_test.js'],

  framework: 'mocha',

  mochaOpts: {
    reporter: 'spec',
    slow: 3000
  }
};<|endoftext|>


<commit_before>// Keith's [Phoenix](https://github.com/sdegutis/Phoenix) config

var modifiers = ["ctrl", "cmd"];
var border = 2;

function fullScreen() {
  var win = Window.focusedWindow();
  var sframe = win.screen().frameIncludingDockAndMenu();
  win.setFrame({
    x: sframe.x,
    y: sframe.y,
    width: sframe.width,
    height: sframe.height
  });
}

function halfSize() {
  var win = Window.focusedWindow();
  var sframe = win.screen().frameIncludingDockAndMenu();
  var wframe = win.frame();
  var originY = sframe.y + (sframe.height - (wframe.height / 2)) / 2;
  win.setFrame({
    x: sframe.x,
    y: originY,
    width: wframe.width / 2,
    height: wframe.height / 2
  });
}

function leftHalf() {
  var win = Window.focusedWindow();
  var sframe = win.screen().frameIncludingDockAndMenu();
  var width =
  win.setFrame({
    x: sframe.x,
    y: sframe.y,
    width: sframe.width / 2 - border,
    height: sframe.height
  });
}

function rightHalf() {
  var win = Window.focusedWindow();
  var sframe = win.screen().frameIncludingDockAndMenu();
  win.setFrame({
    x: sframe.width / 2 + border,
    y: sframe.y,
    width: sframe.width / 2,
    height: sframe.height
  });
}

function topHalf() {
  var win = Window.focusedWindow();
  var sframe = win.screen().frameWithoutDockOrMenu();
  win.setFrame({
    x: sframe.x,
    y: sframe.y,
    width: sframe.width,
    // 18 seems to correct issues with the height because of the given frame?
    height: sframe.height / 2 - 18
  });
}

function bottomHalf() {
  var win = Window.focusedWindow();
  var sframe = win.screen().frameIncludingDockAndMenu();
  win.setFrame({
    x: sframe.x,
    y: sframe.height / 2,
    width: sframe.width,
    height: sframe.height / 2 - border
  });
}

function topLeft() {
  var win = Window.focusedWindow();
  var sframe = win.screen().frameWithoutDockOrMenu();
  win.setFrame({
    x: sframe.x,
    y: sframe.y,
    width: sframe.width / 2 - border,
    height: sframe.height / 2 - border
  });
}

function bottomLeft() {
  var win = Window.focusedWindow();
  var sframe = win.screen().frameWithoutDockOrMenu();
  win.setFrame({
    x: sframe.x,
    y: sframe.y + sframe.height / 2 + border,
    width: sframe.width / 2 - border,
    height: sframe.height / 2 - border
  });
}

function topRight() {
  var win = Window.focusedWindow();
  var sframe = win.screen().frameWithoutDockOrMenu();
  win.setFrame({
    x: sframe.x + sframe.width / 2 + border,
    y: sframe.y,
    width: sframe.width / 2 - border,
    height: sframe.height / 2 - border
  });
}

function bottomRight() {
  var win = Window.focusedWindow();
  var sframe = win.screen().frameWithoutDockOrMenu();
  win.setFrame({
    x: sframe.x + sframe.width / 2 + border,
    y: sframe.y + sframe.height / 2,
    width: sframe.width / 2 - border,
    height: sframe.height / 2 - border
  });
}

api.bind('k', modifiers, function() { fullScreen() });
api.bind('j', modifiers, function() { halfSize() });

api.bind('h', modifiers, function() { leftHalf() });
api.bind('l', modifiers, function() { rightHalf() });
api.bind('i', modifiers, function() { topHalf() });
api.bind('u', modifiers, function() { bottomHalf() });

api.bind('n', modifiers, function() { topLeft() });
api.bind('m', modifiers, function() { bottomLeft() });
api.bind(',', modifiers, function() { topRight() });
api.bind('.', modifiers, function() { bottomRight() });

var moveModifiers = ["ctrl", "alt"];
var resizeModifiers = ["ctrl", "alt", "cmd"];

function nudge(x, y) {
  var win = Window.focusedWindow();
  var wframe = win.frame();
  var xPercent = wframe.width * (x / 100);
  var yPercent = wframe.height * (y / 100);
  win.setFrame({
    x: wframe.x + xPercent,
    y: wframe.y + yPercent,
    width: wframe.width,
    height: wframe.height
  });
}

function resize(w, h) {
  var win = Window.focusedWindow();
  var wframe = win.frame();
  var wPercent = wframe.width * (w / 100);
  var hPercent = wframe.height * (h / 100);
  win.setFrame({
    x: wframe.x,
    y: wframe.y,
    width: wframe.width + wPercent,
    height: wframe.height + hPercent
  });
}

api.bind('left', moveModifiers, function() { nudge(-5, 0) });
api.bind('right', moveModifiers, function() { nudge(+5, 0) });
api.bind('up', moveModifiers, function() { nudge(0, -5) });
api.bind('down', moveModifiers, function() { nudge(0, +5) });

api.bind('left', resizeModifiers, function() { resize(-10, 0) });
api.bind('right', resizeModifiers, function() { resize(+10, 0) });
api.bind('up', resizeModifiers, function() { resize(0, -10) });
api.bind('down', resizeModifiers, function() { resize(0, +10) });
<commit_msg>Open iTerm with phoenix over quicksilver<commit_after>// Keith's [Phoenix](https://github.com/sdegutis/Phoenix) config

var modifiers = ["ctrl", "cmd"];
var border = 2;

function fullScreen() {
  var win = Window.focusedWindow();
  var sframe = win.screen().frameIncludingDockAndMenu();
  win.setFrame({
    x: sframe.x,
    y: sframe.y,
    width: sframe.width,
    height: sframe.height
  });
}

function halfSize() {
  var win = Window.focusedWindow();
  var sframe = win.screen().frameIncludingDockAndMenu();
  var wframe = win.frame();
  var originY = sframe.y + (sframe.height - (wframe.height / 2)) / 2;
  win.setFrame({
    x: sframe.x,
    y: originY,
    width: wframe.width / 2,
    height: wframe.height / 2
  });
}

function leftHalf() {
  var win = Window.focusedWindow();
  var sframe = win.screen().frameIncludingDockAndMenu();
  var width =
  win.setFrame({
    x: sframe.x,
    y: sframe.y,
    width: sframe.width / 2 - border,
    height: sframe.height
  });
}

function rightHalf() {
  var win = Window.focusedWindow();
  var sframe = win.screen().frameIncludingDockAndMenu();
  win.setFrame({
    x: sframe.width / 2 + border,
    y: sframe.y,
    width: sframe.width / 2,
    height: sframe.height
  });
}

function topHalf() {
  var win = Window.focusedWindow();
  var sframe = win.screen().frameWithoutDockOrMenu();
  win.setFrame({
    x: sframe.x,
    y: sframe.y,
    width: sframe.width,
    // 18 seems to correct issues with the height because of the given frame?
    height: sframe.height / 2 - 18
  });
}

function bottomHalf() {
  var win = Window.focusedWindow();
  var sframe = win.screen().frameIncludingDockAndMenu();
  win.setFrame({
    x: sframe.x,
    y: sframe.height / 2,
    width: sframe.width,
    height: sframe.height / 2 - border
  });
}

function topLeft() {
  var win = Window.focusedWindow();
  var sframe = win.screen().frameWithoutDockOrMenu();
  win.setFrame({
    x: sframe.x,
    y: sframe.y,
    width: sframe.width / 2 - border,
    height: sframe.height / 2 - border
  });
}

function bottomLeft() {
  var win = Window.focusedWindow();
  var sframe = win.screen().frameWithoutDockOrMenu();
  win.setFrame({
    x: sframe.x,
    y: sframe.y + sframe.height / 2 + border,
    width: sframe.width / 2 - border,
    height: sframe.height / 2 - border
  });
}

function topRight() {
  var win = Window.focusedWindow();
  var sframe = win.screen().frameWithoutDockOrMenu();
  win.setFrame({
    x: sframe.x + sframe.width / 2 + border,
    y: sframe.y,
    width: sframe.width / 2 - border,
    height: sframe.height / 2 - border
  });
}

function bottomRight() {
  var win = Window.focusedWindow();
  var sframe = win.screen().frameWithoutDockOrMenu();
  win.setFrame({
    x: sframe.x + sframe.width / 2 + border,
    y: sframe.y + sframe.height / 2,
    width: sframe.width / 2 - border,
    height: sframe.height / 2 - border
  });
}

api.bind('k', modifiers, function() { fullScreen() });
api.bind('j', modifiers, function() { halfSize() });

api.bind('h', modifiers, function() { leftHalf() });
api.bind('l', modifiers, function() { rightHalf() });
api.bind('i', modifiers, function() { topHalf() });
api.bind('u', modifiers, function() { bottomHalf() });

api.bind('n', modifiers, function() { topLeft() });
api.bind('m', modifiers, function() { bottomLeft() });
api.bind(',', modifiers, function() { topRight() });
api.bind('.', modifiers, function() { bottomRight() });

var moveModifiers = ["ctrl", "alt"];
var resizeModifiers = ["ctrl", "alt", "cmd"];

function nudge(x, y) {
  var win = Window.focusedWindow();
  var wframe = win.frame();
  var xPercent = wframe.width * (x / 100);
  var yPercent = wframe.height * (y / 100);
  win.setFrame({
    x: wframe.x + xPercent,
    y: wframe.y + yPercent,
    width: wframe.width,
    height: wframe.height
  });
}

function resize(w, h) {
  var win = Window.focusedWindow();
  var wframe = win.frame();
  var wPercent = wframe.width * (w / 100);
  var hPercent = wframe.height * (h / 100);
  win.setFrame({
    x: wframe.x,
    y: wframe.y,
    width: wframe.width + wPercent,
    height: wframe.height + hPercent
  });
}

api.bind('left', moveModifiers, function() { nudge(-5, 0) });
api.bind('right', moveModifiers, function() { nudge(+5, 0) });
api.bind('up', moveModifiers, function() { nudge(0, -5) });
api.bind('down', moveModifiers, function() { nudge(0, +5) });

api.bind('left', resizeModifiers, function() { resize(-10, 0) });
api.bind('right', resizeModifiers, function() { resize(+10, 0) });
api.bind('up', resizeModifiers, function() { resize(0, -10) });
api.bind('down', resizeModifiers, function() { resize(0, +10) });

api.bind('t', moveModifiers, function () { api.launch("iTerm"); });
<|endoftext|>


<commit_before>define(function() {

  var getChannel = function(name) {
    return "flathead:" + name;
  }

  var Ceci = function (element, def) {

    var reserved = ['init', 'listeners', 'defaultListener'];

    Object.keys(def).filter(function (item) {
      return reserved.indexOf(item) === -1;
    }).forEach(function (key) {
      var entry = def[key];
      if (typeof entry === 'function') {
        element[key] = entry;
      }
    });

    if (!def.defaultListener){
      def.defaultListener = Object.keys(def.listeners)[0];
    }

    Object.keys(def.listeners).forEach(function (key) {
      var entry = def.listeners[key];
      var entryType = typeof entry;

      if (entryType === 'function') {
        element[key] = entry;
      }
      else {
        throw "Listener \"" + key + "\" is not a function.";
      }
    });

    if (def.defaultListener){
      element.defaultListener = def.listeners[def.defaultListener];
    }
    else {
      element.defaultListener = function(data){
        console.log("No default listener set");
      }
    }

    element.emit = function (data) {
      var e = new CustomEvent(getChannel(element.broadcastChannel), {bubbles: true, detail: data});
      element.dispatchEvent(e);
      // console.log(element.id + " -> " + element.broadcastChannel);
    };

    element.init = function() {
      if (def.init) {
        def.init.call(element);
      }
    };
  }

  Ceci.defaultChannel = "blue";

  Ceci._components = {};

  function getBroadcastChannel(element) {
    var broadcast = element.getElementsByTagName('broadcast')[0];
    if (broadcast){
      var channel = broadcast.getAttribute("on");
      if (channel) {
        return channel;
      }
    }
    return Ceci.defaultChannel;
  }

  function getSubscriptions(element) {
    var subscriptions = element.getElementsByTagName('listen');
    subscriptions = Array.prototype.slice.call(subscriptions);

    if(subscriptions.length === 0) {
      return [{
        listener: 'defaultListener',
        channel: Ceci.defaultChannel
      }];
    }

    subscriptions = subscriptions.map(function (e) {
      var channel = e.getAttribute("on");
      var listener = e.getAttribute("for");

      return {
        listener: listener,
        channel: (channel ? channel : Ceci.defaultChannel)
      };
    });

    return subscriptions;
  };

  Ceci.convertElement = function (element) {
    var def = Ceci._components[element.localName];
    console.log(def);
    // data channels this element needs to hook into
    element.broadcastChannel = getBroadcastChannel(element);
    element.subscriptions = getSubscriptions(element, def.defaultListener);

    // real content
    element._innerHTML = element.innerHTML;
    element._innerText = element.innerText;
    if (def.template){
      element.innerHTML = def.template.innerHTML;
    }

    def.contructor.call(element, def.initParams | {});

    element.subscriptions.forEach(function (subscription) {

      console.log(
        "Adding event listener for",
        element.id + '.' + subscription.listener + '(<data>)',
        "on",
        subscription.channel
      );
      document.addEventListener(getChannel(subscription.channel), function(e) {
        if(e.target !== element) {
          // console.log(element.id + " <- " + subscription.channel);
          element[subscription.listener](e.detail, subscription.channel);
        }
        return true;
      })
    });

    element.init();
  };

  Ceci.processComponent = function (element) {
    var name = element.getAttribute('name');
    var template = element.querySelector('template');
    var script = element.querySelector('script[type="text/ceci"]');

    try{
      var generator = new Function("Ceci", "return function() {" + script.innerHTML+ "}");
    }
    catch(e){
      if (e.name === 'SyntaxError') {
        e.message += " in definition of component \"" + name + "\".";
        throw e;
      }
      else {
        throw e;
      }
    }
    var contructor = generator(Ceci);

    Ceci._components[name] = {
      template: template,
      contructor: contructor
    };

    var existingElements = document.querySelectorAll(name);
    Array.prototype.forEach.call(existingElements, function (existingElement) {
      Ceci.convertElement(existingElement);
    });
  };

  Ceci.load = function (callback) {
    function scrape (callback) {
      var elements = document.querySelectorAll('element');
      elements = Array.prototype.slice.call(elements);
      elements.forEach(Ceci.processComponent);
      if (callback){
        callback(Ceci._components);
      }
    }

    var ceciLinks = document.querySelectorAll('link[rel=component][type="text/ceci"]');

    if (ceciLinks.length) {
      var linksLeft = ceciLinks.length;
      Array.prototype.forEach.call(ceciLinks, function (componentLink) {
        var xhr = new XMLHttpRequest(),
            docURL = componentLink.getAttribute('href');
        xhr.open('GET', docURL ,true);
        xhr.onload = function (e) {
          var fragment = document.createElement('div');
          fragment.innerHTML = xhr.response;
          if (document.body.firstChild) {
            document.body.insertBefore(fragment, document.body.firstChild);
          }
          else {
            document.body.appendChild(fragment);
          }
          if (--linksLeft === 0) {
            scrape(callback);
          }
        };
        xhr.send(null);
      });
    }
    else {
      scrape(callback);
    }
  };

  return Ceci;
});
<commit_msg>editable attribute-property bindings<commit_after>define(function() {

  var getChannel = function(name) {
    return "flathead:" + name;
  }

  var Ceci = function (element, def) {

    var reserved = ['init', 'listeners', 'defaultListener', 'editable'];

    Object.keys(def).filter(function (item) {
      return reserved.indexOf(item) === -1;
    }).forEach(function (key) {
      var entry = def[key];
      if (typeof entry === 'function') {
        element[key] = entry;
      }
    });

    if (!def.defaultListener){
      def.defaultListener = Object.keys(def.listeners)[0];
    }

    Object.keys(def.listeners).forEach(function (key) {
      var entry = def.listeners[key];
      var entryType = typeof entry;

      if (entryType === 'function') {
        element[key] = entry;
      }
      else {
        throw "Listener \"" + key + "\" is not a function.";
      }
    });

    if (def.defaultListener){
      element.defaultListener = def.listeners[def.defaultListener];
    }
    else {
      element.defaultListener = function(data){
        console.log("No default listener set");
      }
    }

    var elementAttributes = {};

    var bindAttributeChanging = function(target, attrName, fallthrough) {
      // value tracking as "real" value
      var v = false,
          get = function() { return v; },
          set = function(v) {
            target.setAttribute(attrName, v);
          };
      Object.defineProperty(target, attrName, { get: get, set: set });

      // feedback and mutation observing based on HTML attribute
      var handler = function(mutations) {
            mutations.forEach(function(mutation) {
              v = target.getAttribute(attrName);
              fallthrough.call(target, v);
            });
          },
          observer = new MutationObserver(handler),
          config = { attributes: true, attributeFilter: [attrName] };
      observer.observe(target, config);
    };

    if (def.editable) {
      Object.keys(def.editable).forEach(function (key) {
        var props = def.editable[key];
        bindAttributeChanging(element, key, props.edit);
        elementAttributes[key] = props;
      });
    }

    element.getAttributeDefinition = function (attrName) {
      return elementAttributes[attrName];
    }

    element.emit = function (data) {
      var e = new CustomEvent(getChannel(element.broadcastChannel), {bubbles: true, detail: data});
      element.dispatchEvent(e);
      // console.log(element.id + " -> " + element.broadcastChannel);
    };

    element.init = function() {
      if (def.init) {
        def.init.call(element);
      }
    };
  }

  Ceci.defaultChannel = "blue";

  Ceci._components = {};

  function getBroadcastChannel(element) {
    var broadcast = element.getElementsByTagName('broadcast')[0];
    if (broadcast){
      var channel = broadcast.getAttribute("on");
      if (channel) {
        return channel;
      }
    }
    return Ceci.defaultChannel;
  }

  function getSubscriptions(element) {
    var subscriptions = element.getElementsByTagName('listen');
    subscriptions = Array.prototype.slice.call(subscriptions);

    if(subscriptions.length === 0) {
      return [{
        listener: 'defaultListener',
        channel: Ceci.defaultChannel
      }];
    }

    subscriptions = subscriptions.map(function (e) {
      var channel = e.getAttribute("on");
      var listener = e.getAttribute("for");

      return {
        listener: listener,
        channel: (channel ? channel : Ceci.defaultChannel)
      };
    });

    return subscriptions;
  };

  Ceci.convertElement = function (element) {
    var def = Ceci._components[element.localName];
    console.log(def);
    // data channels this element needs to hook into
    element.broadcastChannel = getBroadcastChannel(element);
    element.subscriptions = getSubscriptions(element, def.defaultListener);

    // real content
    element._innerHTML = element.innerHTML;
    element._innerText = element.innerText;
    if (def.template){
      element.innerHTML = def.template.innerHTML;
    }

    def.contructor.call(element, def.initParams | {});

    element.subscriptions.forEach(function (subscription) {

      console.log(
        "Adding event listener for",
        element.id + '.' + subscription.listener + '(<data>)',
        "on",
        subscription.channel
      );
      document.addEventListener(getChannel(subscription.channel), function(e) {
        if(e.target !== element) {
          // console.log(element.id + " <- " + subscription.channel);
          element[subscription.listener](e.detail, subscription.channel);
        }
        return true;
      })
    });

    element.init();
  };

  Ceci.processComponent = function (element) {
    var name = element.getAttribute('name');
    var template = element.querySelector('template');
    var script = element.querySelector('script[type="text/ceci"]');

    try{
      var generator = new Function("Ceci", "return function() {" + script.innerHTML+ "}");
    }
    catch(e){
      if (e.name === 'SyntaxError') {
        e.message += " in definition of component \"" + name + "\".";
        throw e;
      }
      else {
        throw e;
      }
    }
    var contructor = generator(Ceci);

    Ceci._components[name] = {
      template: template,
      contructor: contructor
    };

    var existingElements = document.querySelectorAll(name);
    Array.prototype.forEach.call(existingElements, function (existingElement) {
      Ceci.convertElement(existingElement);
    });
  };

  Ceci.load = function (callback) {
    function scrape (callback) {
      var elements = document.querySelectorAll('element');
      elements = Array.prototype.slice.call(elements);
      elements.forEach(Ceci.processComponent);
      if (callback){
        callback(Ceci._components);
      }
    }

    var ceciLinks = document.querySelectorAll('link[rel=component][type="text/ceci"]');

    if (ceciLinks.length) {
      var linksLeft = ceciLinks.length;
      Array.prototype.forEach.call(ceciLinks, function (componentLink) {
        var xhr = new XMLHttpRequest(),
            docURL = componentLink.getAttribute('href');
        xhr.open('GET', docURL ,true);
        xhr.onload = function (e) {
          var fragment = document.createElement('div');
          fragment.innerHTML = xhr.response;
          if (document.body.firstChild) {
            document.body.insertBefore(fragment, document.body.firstChild);
          }
          else {
            document.body.appendChild(fragment);
          }
          if (--linksLeft === 0) {
            scrape(callback);
          }
        };
        xhr.send(null);
      });
    }
    else {
      scrape(callback);
    }
  };

  return Ceci;
});
<|endoftext|>


<commit_before>// tests for modal pattern
//
// @author Rok Garbas
// @version 1.0
// @licstart  The following is the entire license notice for the JavaScript
//            code in this page.
//
// Copyright (C) 2010 Plone Foundation
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License.
//
// This program 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 General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the Free Software Foundation, Inc., 51
// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
// @licend  The above is the entire license notice for the JavaScript code in
//          this page.
//

/*jshint bitwise:true, curly:true, eqeqeq:true, immed:true, latedef:true,
  newcap:true, noarg:true, noempty:true, nonew:true, plusplus:true,
  regexp:true, undef:true, strict:true, trailing:true, browser:true */
/*global buster:false, require:false, describe:false, it:false, expect:false,
  before:false */

buster.spec.expose();
require([
  'jquery',
  'jam/Patterns/src/registry',
  'js/patterns/autotoc',
  'js/patterns/backdrop',
  'js/patterns/datetime',
  'js/patterns/expose',
  'js/patterns/modal',
  'js/patterns/select2',
  'js/patterns/toggle'
], function($, registry, AutoTOC, Backdrop, DateTime, Expose, Modal, Select2,
      Toggle) {
  "use strict";

  describe("AutoTOC", function () {
    before(function() {
      this.$el = $('' +
        '
' +
        '
' +
        '
Title 1
' +
        '
Title 2
' +
        '
Title 2.1
' +
        '
Title 2.3
' +
        '
Title 2.4
' +
        '
Title 3
' +
        '
Title 3.1
' +
        '
Title 3.1.1
' +
        '
Title 3.1.1.1
' +
        '
Title 4
' +
        '
' +
        '
');
    });
    it("by default creates TOC from h1/h2/h3", function() {
      expect($('> nav', this.$el).size()).toEqual(0);
      registry.scan(this.$el);
      expect($('> nav', this.$el).size()).toEqual(1);
      expect($('> nav > a', this.$el).size()).toEqual(9);
      expect($('> nav > a.autotoc-level-1', this.$el).size()).toEqual(4);
      expect($('> nav > a.autotoc-level-2', this.$el).size()).toEqual(4);
      expect($('> nav > a.autotoc-level-3', this.$el).size()).toEqual(1);
      expect($('> nav > a.autotoc-level-4', this.$el).size()).toEqual(0);
    });
    it("can be used as jQuery plugin as well", function () {
      expect($('> nav', this.$el).size()).toEqual(0);
      this.$el.patAutotoc();
      expect($('> nav', this.$el).size()).toEqual(1);
    });
    it("can have custom levels", function() {
      this.$el.attr('data-pat-autotoc', 'levels:h1');
      expect($('> nav', this.$el).size()).toEqual(0);
      registry.scan(this.$el);
      expect($('> nav', this.$el).size()).toEqual(1);
      expect($('> nav > a.autotoc-level-1', this.$el).size()).toEqual(4);
      expect($('> nav > a.autotoc-level-2', this.$el).size()).toEqual(0);
    });
  });

  describe("Toggle", function() {
    before(function() {
      this.$el = $('' +
        '
' +
        ' Button' +
        '

' +
        '
');
    });
    it("by default toggles on click event", function() {
      expect($('.toggled', this.$el).size()).toEqual(0);
      registry.scan(this.$el);
      expect($('.toggled', this.$el).size()).toEqual(0);
      $('.pat-toggle', this.$el).trigger('click');
      expect($('.toggled', this.$el).size()).toEqual(1);
    });
    it("can also listen to custom event", function() {
      $('.pat-toggle', this.$el).attr('data-pat-toggle',
        $('.pat-toggle', this.$el).attr('data-pat-toggle') + 'event:customEvent;');
      expect($('.toggled', this.$el).size()).toEqual(0);
      registry.scan(this.$el);
      expect($('.toggled', this.$el).size()).toEqual(0);
      $('.pat-toggle', this.$el).trigger('customEvent');
      expect($('.toggled', this.$el).size()).toEqual(1);
    });
    it("can also toggle custom element attribute", function() {
      $('.pat-toggle', this.$el).attr('data-pat-toggle',
        $('.pat-toggle', this.$el).attr('data-pat-toggle') + 'attribute:rel;');
      expect($('.toggled', this.$el).size()).toEqual(0);
      expect($('[rel="toggled"]', this.$el).size()).toEqual(0);
      registry.scan(this.$el);
      expect($('[rel="toggled"]', this.$el).size()).toEqual(0);
      expect($('.toggled', this.$el).size()).toEqual(0);
      $('.pat-toggle', this.$el).trigger('click');
      expect($('.toggled', this.$el).size()).toEqual(0);
      expect($('[rel="toggled"]', this.$el).size()).toEqual(1);
    });
  });

  describe("DateTime", function() {
    before(function() {
      this.$el = $('' +
        '
' +
        ' <input class="pat-datetime" data-pat-datetime="" />' +
        '
');
    });
    it('creates initial structure', function() {
      expect($('.pat-datetime-wrapper', this.$el).size()).toEqual(0);
      registry.scan(this.$el);
      expect($('.pat-datetime-wrapper', this.$el).size()).toEqual(1);
      expect($('.pat-datetime-wrapper select', this.$el).size()).toEqual(8);
      expect($('.pat-datetime-wrapper .pickadate__holder select', this.$el).size()).toEqual(2);
    });
    it('doesn not work on anything else then "input" elements', function() {
      var $el = $('' +
        '
' +
        ' ' +
        '
');
      expect($('.pat-datetime-wrapper', $el).size()).toEqual(0);
      registry.scan($el);
      expect($('.pat-datetime-wrapper', $el).size()).toEqual(0);
    });
  });

  describe("Select2", function() {
    it('tagging', function() {
      var $el = $('' +
        '
' +
        ' <input class="pat-select2" data-pat-select2="tags:Red,Yelow,Blue"' +
        '      value="Yellow" />' +
        '
');
      expect($('.select2-choices', $el).size()).toEqual(0);
      registry.scan($el);
      expect($('.select2-choices', $el).size()).toEqual(1);
      expect($('.select2-choices li', $el).size()).toEqual(2);
    });
  });

  describe("Backdrop", function() {
    it("default behaivour", function() {
      var $el = $('

'),
          backdrop = new Backdrop($el);
      expect($('.backdrop', $el).size()).toEqual(1);
      expect($el.hasClass('backdrop-active')).toBeFalse();
      backdrop.show();
      expect($el.hasClass('backdrop-active')).toBeTrue();
      backdrop.hide();
      expect($el.hasClass('backdrop-active')).toBeFalse();
      backdrop.show();
      expect($el.hasClass('backdrop-active')).toBeTrue();
      backdrop.$backdrop.trigger('click');
      expect($el.hasClass('backdrop-active')).toBeFalse();
      backdrop.show();
      expect($el.hasClass('backdrop-active')).toBeTrue();
      var keydown = $.Event("keydown");
      keydown.keyCode = 50;
      $(document).trigger(keydown);
      expect($el.hasClass('backdrop-active')).toBeTrue();
      keydown.keyCode = 27;
      $(document).trigger(keydown);
      expect($el.hasClass('backdrop-active')).toBeFalse();
    });
  });

  describe("Expose", function() {
    it("default behaivour", function() {
      var $el = $('' +
        '
' +
        ' <form class="pat-expose" data-pat-expose="backdrop:#body;">' +
        '  <input value="" />' +
        ' </form>' +
        '
');
      registry.scan($el);
      expect($('form', $el).css('z-index')).toEqual('');
      expect($('.backdrop', $el).size()).toEqual(1);
      expect($el.hasClass('backdrop-active')).toBeFalse();
      $('input', $el).focus();
      expect($('form', $el).css('z-index')).toEqual('1001');
      expect($el.hasClass('backdrop-active')).toBeTrue();
      var keydown = $.Event("keydown");
      keydown.keyCode = 27;
      $(document).trigger(keydown);
      expect($el.hasClass('backdrop-active')).toBeFalse();
      expect($('form', $el).css('z-index')).toEqual('');
    });
  });

  describe("Modal", function() {
    it("default behaivour", function() {
      var $el = $('' +
        '
' +
        ' Open' +
        '
 Target
' +
        '
');
      registry.scan($el);
      expect($('.modal-wrapper', $el).size()).toEqual(1);
      expect($('.modal', $el).size()).toEqual(0);
      expect($('.backdrop', $el).size()).toEqual(1);
      expect($el.hasClass('backdrop-active')).toBeFalse();
      $('a.pat-modal', $el).click();
      expect($('.modal', $el).size()).toEqual(1);
      expect($el.hasClass('backdrop-active')).toBeTrue();
      var keydown = $.Event("keydown");
      keydown.keyCode = 27;
      $(document).trigger(keydown);
      expect($el.hasClass('backdrop-active')).toBeFalse();
      expect($('.modal', $el).size()).toEqual(0);
    });
  });

  buster.run();

});
<commit_msg>added new test for modal pattern<commit_after>// tests for modal pattern
//
// @author Rok Garbas
// @version 1.0
// @licstart  The following is the entire license notice for the JavaScript
//            code in this page.
//
// Copyright (C) 2010 Plone Foundation
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License.
//
// This program 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 General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the Free Software Foundation, Inc., 51
// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
// @licend  The above is the entire license notice for the JavaScript code in
//          this page.
//

/*jshint bitwise:true, curly:true, eqeqeq:true, immed:true, latedef:true,
  newcap:true, noarg:true, noempty:true, nonew:true, plusplus:true,
  regexp:true, undef:true, strict:true, trailing:true, browser:true */
/*global buster:false, require:false, describe:false, it:false, expect:false,
  before:false, after:false */

buster.spec.expose();
require([
  'jquery',
  'jam/Patterns/src/registry',
  'js/patterns/base',
  'js/patterns/autotoc',
  'js/patterns/backdrop',
  'js/patterns/datetime',
  'js/patterns/expose',
  'js/patterns/modal',
  'js/patterns/select2',
  'js/patterns/toggle'
], function($, registry, Base, AutoTOC, Backdrop, DateTime, Expose, Modal,
      Select2, Toggle) {
  "use strict";

  describe("Base", function () {
    before(function() {
      this._patterns = $.extend({}, registry.patterns);
    });
    after(function() {
      registry.patterns = this._patterns;
    });
    it("read options from dom tree", function() {
      var $el = $('' +
        '
' +
        '

' +
        '
');

      Base.extend({
        name: "example",
        defaults: {
          name3: 'value3'
        },
        init: function() {
          expect(this.options.name1).toEqual('value1');
          expect(this.options.name2).toEqual('something');
          expect(this.options.name3).toEqual('value3');
        }
      });

      registry.scan($el);
    });
  });

  describe("AutoTOC", function () {
    before(function() {
      this.$el = $('' +
        '
' +
        '
' +
        '
Title 1
' +
        '
Title 2
' +
        '
Title 2.1
' +
        '
Title 2.3
' +
        '
Title 2.4
' +
        '
Title 3
' +
        '
Title 3.1
' +
        '
Title 3.1.1
' +
        '
Title 3.1.1.1
' +
        '
Title 4
' +
        '
' +
        '
');
    });
    it("by default creates TOC from h1/h2/h3", function() {
      expect($('> nav', this.$el).size()).toEqual(0);
      registry.scan(this.$el);
      expect($('> nav', this.$el).size()).toEqual(1);
      expect($('> nav > a', this.$el).size()).toEqual(9);
      expect($('> nav > a.autotoc-level-1', this.$el).size()).toEqual(4);
      expect($('> nav > a.autotoc-level-2', this.$el).size()).toEqual(4);
      expect($('> nav > a.autotoc-level-3', this.$el).size()).toEqual(1);
      expect($('> nav > a.autotoc-level-4', this.$el).size()).toEqual(0);
    });
    it("can be used as jQuery plugin as well", function () {
      expect($('> nav', this.$el).size()).toEqual(0);
      this.$el.patAutotoc();
      expect($('> nav', this.$el).size()).toEqual(1);
    });
    it("can have custom levels", function() {
      this.$el.attr('data-pat-autotoc', 'levels:h1');
      expect($('> nav', this.$el).size()).toEqual(0);
      registry.scan(this.$el);
      expect($('> nav', this.$el).size()).toEqual(1);
      expect($('> nav > a.autotoc-level-1', this.$el).size()).toEqual(4);
      expect($('> nav > a.autotoc-level-2', this.$el).size()).toEqual(0);
    });
  });

  describe("Backdrop", function() {
    it("default behaivour", function() {
      var $el = $('

'),
          backdrop = new Backdrop($el);
      expect($('.backdrop', $el).size()).toEqual(1);
      expect($el.hasClass('backdrop-active')).toBeFalse();
      backdrop.show();
      expect($el.hasClass('backdrop-active')).toBeTrue();
      backdrop.hide();
      expect($el.hasClass('backdrop-active')).toBeFalse();
      backdrop.show();
      expect($el.hasClass('backdrop-active')).toBeTrue();
      backdrop.$backdrop.trigger('click');
      expect($el.hasClass('backdrop-active')).toBeFalse();
      backdrop.show();
      expect($el.hasClass('backdrop-active')).toBeTrue();
      var keydown = $.Event("keydown");
      keydown.keyCode = 50;
      $(document).trigger(keydown);
      expect($el.hasClass('backdrop-active')).toBeTrue();
      keydown.keyCode = 27;
      $(document).trigger(keydown);
      expect($el.hasClass('backdrop-active')).toBeFalse();
    });
  });

  describe("DateTime", function() {
    before(function() {
      this.$el = $('' +
        '
' +
        ' <input class="pat-datetime" data-pat-datetime="" />' +
        '
');
    });
    it('creates initial structure', function() {
      expect($('.pat-datetime-wrapper', this.$el).size()).toEqual(0);
      registry.scan(this.$el);
      expect($('.pat-datetime-wrapper', this.$el).size()).toEqual(1);
      expect($('.pat-datetime-wrapper select', this.$el).size()).toEqual(8);
      expect($('.pat-datetime-wrapper .pickadate__holder select', this.$el).size()).toEqual(2);
    });
    it('doesn not work on anything else then "input" elements', function() {
      var $el = $('' +
        '
' +
        ' ' +
        '
');
      expect($('.pat-datetime-wrapper', $el).size()).toEqual(0);
      registry.scan($el);
      expect($('.pat-datetime-wrapper', $el).size()).toEqual(0);
    });
  });

  describe("Expose", function() {
    it("default behaivour", function() {
      var $el = $('' +
        '
' +
        ' <form class="pat-expose" data-pat-expose="backdrop:#body;">' +
        '  <input value="" />' +
        ' </form>' +
        '
');
      registry.scan($el);
      expect($('form', $el).css('z-index')).toEqual('');
      expect($('.backdrop', $el).size()).toEqual(1);
      expect($el.hasClass('backdrop-active')).toBeFalse();
      $('input', $el).focus();
      expect($('form', $el).css('z-index')).toEqual('1001');
      expect($el.hasClass('backdrop-active')).toBeTrue();
      var keydown = $.Event("keydown");
      keydown.keyCode = 27;
      $(document).trigger(keydown);
      expect($el.hasClass('backdrop-active')).toBeFalse();
      expect($('form', $el).css('z-index')).toEqual('');
    });
  });

  describe("Modal", function() {
    it("default behaivour", function() {
      var $el = $('' +
        '
' +
        ' Open' +
        '
Target
' +
        '
');
      registry.scan($el);
      expect($('.modal-wrapper', $el).size()).toEqual(1);
      expect($('.modal', $el).size()).toEqual(0);
      expect($('.backdrop', $el).size()).toEqual(1);
      expect($el.hasClass('backdrop-active')).toBeFalse();
      $('a.pat-modal', $el).click();
      expect($('.modal', $el).size()).toEqual(1);
      expect($el.hasClass('backdrop-active')).toBeTrue();
      var keydown = $.Event("keydown");
      keydown.keyCode = 27;
      $(document).trigger(keydown);
      expect($el.hasClass('backdrop-active')).toBeFalse();
      expect($('.modal', $el).size()).toEqual(0);
    });
    it("modal with custom template", function() {
      var $el = $('' +
        '
' +
        ' Open' +
        '
 Target
' +
        '
');

      $('a.pat-modal', $el).patModal({
        template: function($modal) {
          var contents = $modal.html();
          $modal
            .html('')
            .append($('

Title

'))
            .append($('

'))
            .append($('

'));
          $('.modal-body', $modal).html(contents);
        }
      });

      $('a.pat-modal', $el).click();

      expect($('.modal', $el).size()).toEqual(1);
      expect($('.modal .modal-header', $el).size()).toEqual(1);
      expect($('.modal .modal-body', $el).size()).toEqual(1);
      expect($('.modal .modal-footer', $el).size()).toEqual(1);

    });
  });

  describe("Select2", function() {
    it('tagging', function() {
      var $el = $('' +
        '
' +
        ' <input class="pat-select2" data-pat-select2="tags:Red,Yelow,Blue"' +
        '      value="Yellow" />' +
        '
');
      expect($('.select2-choices', $el).size()).toEqual(0);
      registry.scan($el);
      expect($('.select2-choices', $el).size()).toEqual(1);
      expect($('.select2-choices li', $el).size()).toEqual(2);
    });
  });

  describe("Toggle", function() {
    before(function() {
      this.$el = $('' +
        '
' +
        ' Button' +
        '

' +
        '
');
    });
    it("by default toggles on click event", function() {
      expect($('.toggled', this.$el).size()).toEqual(0);
      registry.scan(this.$el);
      expect($('.toggled', this.$el).size()).toEqual(0);
      $('.pat-toggle', this.$el).trigger('click');
      expect($('.toggled', this.$el).size()).toEqual(1);
    });
    it("can also listen to custom event", function() {
      $('.pat-toggle', this.$el).attr('data-pat-toggle',
        $('.pat-toggle', this.$el).attr('data-pat-toggle') + 'event:customEvent;');
      expect($('.toggled', this.$el).size()).toEqual(0);
      registry.scan(this.$el);
      expect($('.toggled', this.$el).size()).toEqual(0);
      $('.pat-toggle', this.$el).trigger('customEvent');
      expect($('.toggled', this.$el).size()).toEqual(1);
    });
    it("can also toggle custom element attribute", function() {
      $('.pat-toggle', this.$el).attr('data-pat-toggle',
        $('.pat-toggle', this.$el).attr('data-pat-toggle') + 'attribute:rel;');
      expect($('.toggled', this.$el).size()).toEqual(0);
      expect($('[rel="toggled"]', this.$el).size()).toEqual(0);
      registry.scan(this.$el);
      expect($('[rel="toggled"]', this.$el).size()).toEqual(0);
      expect($('.toggled', this.$el).size()).toEqual(0);
      $('.pat-toggle', this.$el).trigger('click');
      expect($('.toggled', this.$el).size()).toEqual(0);
      expect($('[rel="toggled"]', this.$el).size()).toEqual(1);
    });
  });

  buster.run();

});
<|endoftext|>