<commit_before>'use strict';

const _ = require('lodash');

const RNFetchBlob = require('react-native-fetch-blob').default;

const {
    fs
} = RNFetchBlob;

const baseCacheDir = fs.dirs.CacheDir + '/imagesCacheDir';

const SHA1 = require("crypto-js/sha1");
const URL = require('url-parse');

const defaultHeaders = {};
const defaultImageTypes = ['png', 'jpeg', 'jpg', 'gif', 'bmp', 'tiff', 'tif'];
const defaultResolveHeaders = _.constant(defaultHeaders);

const defaultOptions = {
    useQueryParamsInCacheKey: false
};

const activeDownloads = {};

function serializeObjectKeys(obj) {
    return _(obj)
        .toPairs()
        .sortBy(a => a[0])
        .map(a => a[1])
        .value();
}

function getQueryForCacheKey(url, useQueryParamsInCacheKey) {
    if (_.isArray(useQueryParamsInCacheKey)) {
        return serializeObjectKeys(_.pick(url.query, useQueryParamsInCacheKey));
    }
    if (useQueryParamsInCacheKey) {
        return serializeObjectKeys(url.query);
    }
    return '';
}

function generateCacheKey(url, options) {
    const parsedUrl = new URL(url, null, true);

    const pathParts = parsedUrl.pathname.split('/');

    // last path part is the file name
    const fileName = pathParts.pop();
    const filePath = pathParts.join('/');

    const parts = fileName.split('.');
    const fileType = parts.length > 1 ? _.toLower(parts.pop()) : '';
    const type = defaultImageTypes.includes(fileType) ? fileType : 'jpg';

    const cacheable = filePath + fileName + type + getQueryForCacheKey(parsedUrl, options.useQueryParamsInCacheKey);
    return SHA1(cacheable) + '.' + type;
}

function getCachePath(url, options) {
    if (options.cacheGroup) {
        return options.cacheGroup;
    }
    const {
        host
    } = new URL(url);
    return host.replace(/[^a-z0-9]/gi, '').toLowerCase();
}

function getCachedImageFilePath(url, options) {
    const cachePath = getCachePath(url, options);
    const cacheKey = generateCacheKey(url, options);

    return `${baseCacheDir}/${cachePath}/${cacheKey}`;
}

function deleteFile(filePath) {
    return fs.stat(filePath)
        .then(res => res && res.type === 'file')
        .then(exists => exists && fs.unlink(filePath))
        .catch((err) => {
            // swallow error to always resolve
        });
}

function getDirPath(filePath) {
    return _.initial(filePath.split('/')).join('/');
}

function ensurePath(dirPath) {
    return fs.isDir(dirPath)
        .then(exists =>
            !exists && fs.mkdir(dirPath)
        )
        .catch(err => {
            // swallow folder already exists errors
            if (err.message.includes('folder already exists')) {
                return;
            }
            throw err;
        });
}

/**
 * returns a promise that is resolved when the download of the requested file
 * is complete and the file is saved.
 * if the download fails, or was stopped the partial file is deleted, and the
 * promise is rejected
 * @param fromUrl   String source url
 * @param toFile    String destination path
 * @param headers   Object headers to use when downloading the file
 * @returns {Promise}
 */
function downloadImage(fromUrl, toFile, headers = {}) {
    // use toFile as the key as is was created using the cacheKey
    if (!_.has(activeDownloads, toFile)) {
        // create an active download for this file
        activeDownloads[toFile] = new Promise((resolve, reject) => {
            RNFetchBlob
                .config({path: toFile})
                .fetch('GET', fromUrl, headers)
                .then(res => {
                    if (Math.floor(res.respInfo.status / 100) !== 2) {
                        throw new Error('Failed to successfully download image');
                    }
                    resolve(toFile);
                })
                .catch(err => {
                    return deleteFile(toFile)
                        .then(() => reject(err));
                })
                .finally(() => {
                    // cleanup
                    delete activeDownloads[toFile];
                });
        });
    }
    return activeDownloads[toFile];
}

function createPrefetcer(list) {
    const urls = _.clone(list);
    return {
        next() {
            return urls.shift();
        }
    };
}

function runPrefetchTask(prefetcher, options) {
    const url = prefetcher.next();
    if (!url) {
        return Promise.resolve();
    }
    // if url is cacheable - cache it
    if (isCacheable(url)) {
        // check cache
        return getCachedImagePath(url, options)
        // if not found download
            .catch(() => cacheImage(url, options))
            // allow prefetch task to fail without terminating other prefetch tasks
            .catch(_.noop)
            // then run next task
            .then(() => runPrefetchTask(prefetcher, options));
    }
    // else get next
    return runPrefetchTask(prefetcher, options);
}

function collectFilesInfo(basePath) {
    return fs.stat(basePath)
        .then((info) => {
            if (info.type === 'file') {
                return [info];
            }
            return fs.ls(basePath)
                .then(files => {
                    const promises = _.map(files, file => {
                        return collectFilesInfo(`${basePath}/${file}`);
                    });
                    return Promise.all(promises);
                });
        })
        .catch(err => {
            return [];
        });
}

// API

/**
 * Check whether a url is cacheable.
 * Takes an image source and if it's a valid url return `true`
 * @param url
 * @returns {boolean}
 */
function isCacheable(url) {
    return _.isString(url) && (_.startsWith(url, 'http://') || _.startsWith(url, 'https://'));
}

/**
 * Get the local path corresponding to the given url and options.
 * @param url
 * @param options
 * @returns {Promise.<String>}
 */
function getCachedImagePath(url, options = defaultOptions) {
    const filePath = getCachedImageFilePath(url, options);
    return fs.stat(filePath)
        .then(res => {
            if (res.type !== 'file') {
                // reject the promise if res is not a file
                throw new Error('Failed to get image from cache');
            }
            if (!res.size) {
                // something went wrong with the download, file size is 0, remove it
                return deleteFile(filePath)
                    .then(() => {
                        throw new Error('Failed to get image from cache');
                    });
            }
            return filePath;
        })
        .catch(err => {
            throw err;
        })
}

/**
 * Download the image to the cache and return the local file path.
 * @param url
 * @param options
 * @param resolveHeaders
 * @returns {Promise.<String>}
 */
function cacheImage(url, options = defaultOptions, resolveHeaders = defaultResolveHeaders) {
    const filePath = getCachedImageFilePath(url, options);
    const dirPath = getDirPath(filePath);
    return ensurePath(dirPath)
        .then(() => resolveHeaders())
        .then(headers => downloadImage(url, filePath, headers));
}

/**
 * Delete the cached image corresponding to the given url and options.
 * @param url
 * @param options
 * @returns {Promise}
 */
function deleteCachedImage(url, options = defaultOptions) {
    const filePath = getCachedImageFilePath(url, options);
    return deleteFile(filePath);
}

/**
 * Cache an array of urls.
 * Usually used to prefetch images.
 * @param urls
 * @param options
 * @returns {Promise}
 */
function cacheMultipleImages(urls, options = defaultOptions) {
    const prefetcher = createPrefetcer(urls);
    const numberOfWorkers = urls.length;
    const promises = _.times(numberOfWorkers, () =>
        runPrefetchTask(prefetcher, options)
    );
    return Promise.all(promises);
}

/**
 * Delete an array of cached images by their urls.
 * Usually used to clear the prefetched images.
 * @param urls
 * @param options
 * @returns {Promise}
 */
function deleteMultipleCachedImages(urls, options = defaultOptions) {
    return _.reduce(urls, (p, url) =>
            p.then(() => deleteCachedImage(url, options)),
        Promise.resolve()
    );
}

/**
* Seed the cache of a specified url with a local image
* Handy if you have a local copy of a remote image, e.g. you just uploaded local to url.
* @param local
* @param url
* @param options
* @returns {Promise}
*/
function seedCache(local, url, options = defaultOptions) {
  const filePath = getCachedImageFilePath(url, options);
  const dirPath = getDirPath(filePath);
  return ensurePath(dirPath)
    .then(() => fs.cp(local, filePath))
}

/**
 * Clear the entire cache.
 * @returns {Promise}
 */
function clearCache() {
    return fs.unlink(baseCacheDir)
        .catch(() => {
            // swallow exceptions if path doesn't exist
        })
        .then(() => ensurePath(baseCacheDir));
}

/**
 * Return info about the cache, list of files and the total size of the cache.
 * @returns {Promise.<{size}>}
 */
function getCacheInfo() {
    return ensurePath(baseCacheDir)
        .then(() => collectFilesInfo(baseCacheDir))
        .then(cache => {
            const files = _.flattenDeep(cache);
            const size = _.sumBy(files, 'size');
            return {
                files,
                size
            };
        });
}

module.exports = {
    isCacheable,
    getCachedImagePath,
    cacheImage,
    deleteCachedImage,
    cacheMultipleImages,
    deleteMultipleCachedImages,
    clearCache,
    seedCache,
    getCacheInfo
};
<commit_msg>Export ImageCacheProvider.generateCacheKey & ImageCacheProvider.getCachedImageFilePath<commit_after>'use strict';

const _ = require('lodash');

const RNFetchBlob = require('react-native-fetch-blob').default;

const {
    fs
} = RNFetchBlob;

const baseCacheDir = fs.dirs.CacheDir + '/imagesCacheDir';

const SHA1 = require("crypto-js/sha1");
const URL = require('url-parse');

const defaultHeaders = {};
const defaultImageTypes = ['png', 'jpeg', 'jpg', 'gif', 'bmp', 'tiff', 'tif'];
const defaultResolveHeaders = _.constant(defaultHeaders);

const defaultOptions = {
    useQueryParamsInCacheKey: false
};

const activeDownloads = {};

function serializeObjectKeys(obj) {
    return _(obj)
        .toPairs()
        .sortBy(a => a[0])
        .map(a => a[1])
        .value();
}

function getQueryForCacheKey(url, useQueryParamsInCacheKey) {
    if (_.isArray(useQueryParamsInCacheKey)) {
        return serializeObjectKeys(_.pick(url.query, useQueryParamsInCacheKey));
    }
    if (useQueryParamsInCacheKey) {
        return serializeObjectKeys(url.query);
    }
    return '';
}

function generateCacheKey(url, options) {
    const parsedUrl = new URL(url, null, true);

    const pathParts = parsedUrl.pathname.split('/');

    // last path part is the file name
    const fileName = pathParts.pop();
    const filePath = pathParts.join('/');

    const parts = fileName.split('.');
    const fileType = parts.length > 1 ? _.toLower(parts.pop()) : '';
    const type = defaultImageTypes.includes(fileType) ? fileType : 'jpg';

    const cacheable = filePath + fileName + type + getQueryForCacheKey(parsedUrl, options.useQueryParamsInCacheKey);
    return SHA1(cacheable) + '.' + type;
}

function getCachePath(url, options) {
    if (options.cacheGroup) {
        return options.cacheGroup;
    }
    const {
        host
    } = new URL(url);
    return host.replace(/[^a-z0-9]/gi, '').toLowerCase();
}

function getCachedImageFilePath(url, options) {
    const cachePath = getCachePath(url, options);
    const cacheKey = generateCacheKey(url, options);

    return `${baseCacheDir}/${cachePath}/${cacheKey}`;
}

function deleteFile(filePath) {
    return fs.stat(filePath)
        .then(res => res && res.type === 'file')
        .then(exists => exists && fs.unlink(filePath))
        .catch((err) => {
            // swallow error to always resolve
        });
}

function getDirPath(filePath) {
    return _.initial(filePath.split('/')).join('/');
}

function ensurePath(dirPath) {
    return fs.isDir(dirPath)
        .then(exists =>
            !exists && fs.mkdir(dirPath)
        )
        .catch(err => {
            // swallow folder already exists errors
            if (err.message.includes('folder already exists')) {
                return;
            }
            throw err;
        });
}

/**
 * returns a promise that is resolved when the download of the requested file
 * is complete and the file is saved.
 * if the download fails, or was stopped the partial file is deleted, and the
 * promise is rejected
 * @param fromUrl   String source url
 * @param toFile    String destination path
 * @param headers   Object headers to use when downloading the file
 * @returns {Promise}
 */
function downloadImage(fromUrl, toFile, headers = {}) {
    // use toFile as the key as is was created using the cacheKey
    if (!_.has(activeDownloads, toFile)) {
        // create an active download for this file
        activeDownloads[toFile] = new Promise((resolve, reject) => {
            RNFetchBlob
                .config({path: toFile})
                .fetch('GET', fromUrl, headers)
                .then(res => {
                    if (Math.floor(res.respInfo.status / 100) !== 2) {
                        throw new Error('Failed to successfully download image');
                    }
                    resolve(toFile);
                })
                .catch(err => {
                    return deleteFile(toFile)
                        .then(() => reject(err));
                })
                .finally(() => {
                    // cleanup
                    delete activeDownloads[toFile];
                });
        });
    }
    return activeDownloads[toFile];
}

function createPrefetcer(list) {
    const urls = _.clone(list);
    return {
        next() {
            return urls.shift();
        }
    };
}

function runPrefetchTask(prefetcher, options) {
    const url = prefetcher.next();
    if (!url) {
        return Promise.resolve();
    }
    // if url is cacheable - cache it
    if (isCacheable(url)) {
        // check cache
        return getCachedImagePath(url, options)
        // if not found download
            .catch(() => cacheImage(url, options))
            // allow prefetch task to fail without terminating other prefetch tasks
            .catch(_.noop)
            // then run next task
            .then(() => runPrefetchTask(prefetcher, options));
    }
    // else get next
    return runPrefetchTask(prefetcher, options);
}

function collectFilesInfo(basePath) {
    return fs.stat(basePath)
        .then((info) => {
            if (info.type === 'file') {
                return [info];
            }
            return fs.ls(basePath)
                .then(files => {
                    const promises = _.map(files, file => {
                        return collectFilesInfo(`${basePath}/${file}`);
                    });
                    return Promise.all(promises);
                });
        })
        .catch(err => {
            return [];
        });
}

// API

/**
 * Check whether a url is cacheable.
 * Takes an image source and if it's a valid url return `true`
 * @param url
 * @returns {boolean}
 */
function isCacheable(url) {
    return _.isString(url) && (_.startsWith(url, 'http://') || _.startsWith(url, 'https://'));
}

/**
 * Get the local path corresponding to the given url and options.
 * @param url
 * @param options
 * @returns {Promise.<String>}
 */
function getCachedImagePath(url, options = defaultOptions) {
    const filePath = getCachedImageFilePath(url, options);
    return fs.stat(filePath)
        .then(res => {
            if (res.type !== 'file') {
                // reject the promise if res is not a file
                throw new Error('Failed to get image from cache');
            }
            if (!res.size) {
                // something went wrong with the download, file size is 0, remove it
                return deleteFile(filePath)
                    .then(() => {
                        throw new Error('Failed to get image from cache');
                    });
            }
            return filePath;
        })
        .catch(err => {
            throw err;
        })
}

/**
 * Download the image to the cache and return the local file path.
 * @param url
 * @param options
 * @param resolveHeaders
 * @returns {Promise.<String>}
 */
function cacheImage(url, options = defaultOptions, resolveHeaders = defaultResolveHeaders) {
    const filePath = getCachedImageFilePath(url, options);
    const dirPath = getDirPath(filePath);
    return ensurePath(dirPath)
        .then(() => resolveHeaders())
        .then(headers => downloadImage(url, filePath, headers));
}

/**
 * Delete the cached image corresponding to the given url and options.
 * @param url
 * @param options
 * @returns {Promise}
 */
function deleteCachedImage(url, options = defaultOptions) {
    const filePath = getCachedImageFilePath(url, options);
    return deleteFile(filePath);
}

/**
 * Cache an array of urls.
 * Usually used to prefetch images.
 * @param urls
 * @param options
 * @returns {Promise}
 */
function cacheMultipleImages(urls, options = defaultOptions) {
    const prefetcher = createPrefetcer(urls);
    const numberOfWorkers = urls.length;
    const promises = _.times(numberOfWorkers, () =>
        runPrefetchTask(prefetcher, options)
    );
    return Promise.all(promises);
}

/**
 * Delete an array of cached images by their urls.
 * Usually used to clear the prefetched images.
 * @param urls
 * @param options
 * @returns {Promise}
 */
function deleteMultipleCachedImages(urls, options = defaultOptions) {
    return _.reduce(urls, (p, url) =>
            p.then(() => deleteCachedImage(url, options)),
        Promise.resolve()
    );
}

/**
* Seed the cache of a specified url with a local image
* Handy if you have a local copy of a remote image, e.g. you just uploaded local to url.
* @param local
* @param url
* @param options
* @returns {Promise}
*/
function seedCache(local, url, options = defaultOptions) {
  const filePath = getCachedImageFilePath(url, options);
  const dirPath = getDirPath(filePath);
  return ensurePath(dirPath)
    .then(() => fs.cp(local, filePath))
}

/**
 * Clear the entire cache.
 * @returns {Promise}
 */
function clearCache() {
    return fs.unlink(baseCacheDir)
        .catch(() => {
            // swallow exceptions if path doesn't exist
        })
        .then(() => ensurePath(baseCacheDir));
}

/**
 * Return info about the cache, list of files and the total size of the cache.
 * @returns {Promise.<{size}>}
 */
function getCacheInfo() {
    return ensurePath(baseCacheDir)
        .then(() => collectFilesInfo(baseCacheDir))
        .then(cache => {
            const files = _.flattenDeep(cache);
            const size = _.sumBy(files, 'size');
            return {
                files,
                size
            };
        });
}

module.exports = {
    isCacheable,
    generateCacheKey,
    getCachedImageFilePath,
    getCachedImagePath,
    cacheImage,
    deleteCachedImage,
    cacheMultipleImages,
    deleteMultipleCachedImages,
    clearCache,
    seedCache,
    getCacheInfo
};
<|endoftext|>


<commit_before>(function(exports) {

    // Network Codes ----------------------------------------------------------
    var Network = {

        Client: {
            Ping: 1,
            Pong: 2
        },

        Game: {

            Tick: {
                Limit: 3,
                Confirm: 4
            },

            Action: {
                Client: 5,
                Server: 6
            },

            Start: 7,

            Player: {
                Info: 8,
                Update: 9,
                Left: 10
            }

        },

        Session: {
            Token: 20,
            Create: 21,
            Join: 22,
            Start: 23,
            Leave: 24,
            Close: 25,

            Update: 27,
            Player: {
                Left: 28,
                Joined: 29
            },

            List: 31,

            Joined: 32,
            Started: 33,
            Left: 35,
            Closed: 36,
            Ready: 37,
            NotReady: 38
        },

        Login: {
            Client: 200,
            Server: 201
        },

        Err: 100,

        Error: {

            Offline: 10,

            Session: {
                Exists: 20,
                NotFound: 21,
                Invalid: 22,
                NotOwner: 23,
                Running: 24,
                Ready: 25,
                NotReady: 26
            },

            Login: {
                Format: 30,
                Version: 31,
                Username: 32,
                Game: 33,
                Persona: 34,
                Token: 35
            }
        }

    };

    Object.defineProperty(Network, 'Event', {
        get: function() {
            throw new Error();
        }
    });

    exports.Network = Network;

})(typeof exports !== 'undefined' ? exports : this);

<commit_msg>Update network constants<commit_after>(function(exports) {

    // Network Codes ----------------------------------------------------------
    var Network = {

        Client: {
            Ping: 1,
            Pong: 2,
            Sync: 3
        },

        Game: {

            Tick: {
                Limit: 4,
                Confirm: 5
            },

            Action: {
                Client: 6,
                Server: 7
            },

            Start: 8,

            Player: {
                Update: 10,
                Left: 11
            }

        },

        // TODO re-organize these
        Session: {

            Token: 20,
            Create: 21,
            Join: 22,
            Start: 23,
            Leave: 24,
            Close: 25,

            Update: 27,

            Player: {
                Left: 28,
                Joined: 29
            },

            List: 31,

            // Move under "Action"
            Joined: 32,
            Started: 33,
            Left: 35,
            Closed: 36,
            Ready: 37,
            NotReady: 38
        },

        Login: {
            Client: 200,
            Server: 201
        },

        Err: 100,

        Error: {

            Offline: 10,

            Session: {
                Exists: 20,
                NotFound: 21,
                Invalid: 22,
                NotOwner: 23,
                Running: 24,
                Ready: 25,
                NotReady: 26
            },

            Login: {
                Format: 30,
                Version: 31,
                Username: 32,
                Game: 33,
                Persona: 34,
                Token: 35
            }
        }

    };

    Object.defineProperty(Network, 'Event', {
        get: function() {
            throw new Error();
        }
    });

    exports.Network = Network;

})(typeof exports !== 'undefined' ? exports : this);

<|endoftext|>


<commit_before>{
    "package": "anim",
    "name": "anim",
    "doc": "http://docs.kissyui.com/docs/html/api/core/anim/index.html",
    "desc": "",
    "tip": "",
    "demo": [
        {
			"title":"动画demo",
			"code":"http://jsbin.com/mayuhezo/3/edit?html,js,console"
		}
    ]
}
<commit_msg>Update anim.js<commit_after>{
    "package": "anim",
    "name": "anim",
    "doc": "http://docs.kissyui.com/docs/html/api/core/anim/index.html",
    "desc": "",
    "tip": "",
    "demo": [
        {
		"title":"动画demo",
		"code":"http://jsbin.com/mayuhezo/3/edit?html,js,console"
	}
    ]
}
<|endoftext|>


<commit_before>import _ from 'underscore'
import moment from 'moment-timezone'
import {
  AccountStore,
  NylasAPI,
  NylasAPIRequest,
} from 'nylas-exports'
import RefreshingJSONCache from './refreshing-json-cache'

// Stores contact rankings
class ContactRankingsCache extends RefreshingJSONCache {
  constructor(accountId) {
    super({
      key: `ContactRankingsFor${accountId}`,
      version: 1,
      refreshInterval: moment.duration(60, 'seconds').asMilliseconds(),
      maxRefreshInterval: moment.duration(24, 'hours').asMilliseconds(),
    })
    this._accountId = accountId
  }

  _nextRefreshInterval() {
    // For the first 15 minutes, refresh roughly once every minute so that the
    // experience of composing drafts during initial is less annoying.
    const initialLimit = (60 * 1000) + 15;
    if (this.refreshInterval < initialLimit) {
      return this.refreshInterval + 1;
    }
    // After the first 15 minutes, refresh twice as long each time up to the max.
    return Math.min(this.refreshInterval * 2, this.maxRefreshInterval);
  }

  fetchData = (callback) => {
    if (NylasEnv.inSpecMode()) return

    const request = new NylasAPIRequest({
      api: NylasAPI,
      options: {
        accountId: this._accountId,
        path: "/contacts/rankings",
      },
    })

    request.run()
    .then((json) => {
      if (!json || !(json instanceof Array)) return

      // Convert rankings into the format needed for quick lookup
      const rankings = {}
      for (const [email, rank] of json) {
        rankings[email.toLowerCase()] = rank
      }
      callback(rankings)

      this.refreshInterval = this._nextRefreshInterval();
    })
    .catch((err) => {
      console.warn(`Request for Contact Rankings failed for
                    account ${this._accountId}. ${err}`)
    })
  }
}

class ContactRankingsCacheManager {
  constructor() {
    this.accountCaches = {};
    this.unsubscribers = [];
    this.onAccountsChanged = _.debounce(this.onAccountsChanged, 100);
  }

  activate() {
    this.onAccountsChanged();
    this.unsubscribers = [AccountStore.listen(this.onAccountsChanged)];
  }

  deactivate() {
    this.unsubscribers.forEach(unsub => unsub());
  }

  onAccountsChanged = () => {
    const previousIDs = Object.keys(this.accountCaches);
    const latestIDs = AccountStore.accounts().map(a => a.id);
    if (_.isEqual(previousIDs, latestIDs)) {
      return;
    }

    const newIDs = _.difference(latestIDs, previousIDs);
    const removedIDs = _.difference(previousIDs, latestIDs);

    console.log(`ContactRankingsCache: Updating contact rankings; added = ${latestIDs}, removed = ${removedIDs}`);

    for (const newID of newIDs) {
      this.accountCaches[newID] = new ContactRankingsCache(newID);
      this.accountCaches[newID].start();
    }

    for (const removedID of removedIDs) {
      this.accountCaches[removedID].end();
      this.accountCaches[removedID] = null;
    }
  }
}

export default new ContactRankingsCacheManager();
<commit_msg>[client-app] Don't hit contact rankings endpoint until account is ready<commit_after>import _ from 'underscore'
import moment from 'moment-timezone'
import {
  AccountStore,
  NylasAPI,
  NylasAPIRequest,
  FolderSyncProgressStore,
} from 'nylas-exports'
import RefreshingJSONCache from './refreshing-json-cache'

// Stores contact rankings
class ContactRankingsCache extends RefreshingJSONCache {
  constructor(accountId) {
    super({
      key: `ContactRankingsFor${accountId}`,
      version: 1,
      refreshInterval: moment.duration(60, 'seconds').asMilliseconds(),
      maxRefreshInterval: moment.duration(24, 'hours').asMilliseconds(),
    })
    this._accountId = accountId
  }

  _nextRefreshInterval() {
    // For the first 15 minutes, refresh roughly once every minute so that the
    // experience of composing drafts during initial is less annoying.
    const initialLimit = (60 * 1000) + 15;
    if (this.refreshInterval < initialLimit) {
      return this.refreshInterval + 1;
    }
    // After the first 15 minutes, refresh twice as long each time up to the max.
    return Math.min(this.refreshInterval * 2, this.maxRefreshInterval);
  }

  fetchData = (callback) => {
    if (NylasEnv.inSpecMode()) return

    const request = new NylasAPIRequest({
      api: NylasAPI,
      options: {
        accountId: this._accountId,
        path: "/contacts/rankings",
      },
    })

    request.run()
    .then((json) => {
      if (!json || !(json instanceof Array)) return

      // Convert rankings into the format needed for quick lookup
      const rankings = {}
      for (const [email, rank] of json) {
        rankings[email.toLowerCase()] = rank
      }
      callback(rankings)

      this.refreshInterval = this._nextRefreshInterval();
    })
    .catch((err) => {
      console.warn(`Request for Contact Rankings failed for
                    account ${this._accountId}. ${err}`)
    })
  }
}

class ContactRankingsCacheManager {
  constructor() {
    this.accountCaches = {};
    this.unsubscribers = [];
    this.onAccountsChanged = _.debounce(this.onAccountsChanged, 100);
  }

  activate() {
    this.onAccountsChanged();
    this.unsubscribers = [AccountStore.listen(this.onAccountsChanged)];
  }

  deactivate() {
    this.unsubscribers.forEach(unsub => unsub());
  }

  onAccountsChanged = async () => {
    const previousIDs = Object.keys(this.accountCaches);
    const latestIDs = AccountStore.accounts().map(a => a.id);
    if (_.isEqual(previousIDs, latestIDs)) {
      return;
    }

    const newIDs = _.difference(latestIDs, previousIDs);
    const removedIDs = _.difference(previousIDs, latestIDs);

    console.log(`ContactRankingsCache: Updating contact rankings; added = ${latestIDs}, removed = ${removedIDs}`);

    for (const newID of newIDs) {
      // Wait until the account has started syncing before trying to fetch
      // contact rankings
      await FolderSyncProgressStore.whenCategoryListSynced(newID)
      this.accountCaches[newID] = new ContactRankingsCache(newID);
      this.accountCaches[newID].start();
    }

    for (const removedID of removedIDs) {
      if (this.accountCaches[removedID]) {
        this.accountCaches[removedID].end();
        this.accountCaches[removedID] = null;
      }
    }
  }
}

export default new ContactRankingsCacheManager();
<|endoftext|>


<commit_before>import Base from 'simple-auth/stores/base';
import objectsAreEqual from 'simple-auth/utils/objects-are-equal';
import Configuration from './../configuration';

/**
  Store that saves its data in a cookie.

  __In order to keep multiple tabs/windows of an application in sync, this
  store has to periodically (every 500ms) check the cookie__ for changes as
  there are no events that notify of changes in cookies. The recommended
  alternative is `Stores.LocalStorage` that also persistently stores data but
  instead of cookies relies on the `localStorage` API and does not need to poll
  for external changes.

  By default the cookie store will use a session cookie that expires and is
  deleted when the browser is closed. The cookie expiration period can be
  configured via setting
  [`Stores.Cooke#cookieExpirationTime`](#SimpleAuth-Stores-Cookie-cookieExpirationTime)
  though. This can also be used to implement "remember me" functionality that
  will either store the session persistently or in a session cookie depending
  whether the user opted in or not:

  ```js
  // app/controllers/login.js
  import LoginControllerMixin from 'simple-auth/mixins/login-controller-mixin';

  export default Ember.Controller.extend(LoginControllerMixin, {
    rememberMe: false,

    rememberMeChanged: function() {
      this.get('session.store').cookieExpirationTime = this.get('rememberMe') ? (14 * 24 * 60 * 60) : null;
    }.observes('rememberMe')
  });
  ```

  _The factory for this store is registered as
  `'simple-auth-session-store:cookie'` in Ember's container._

  @class Cookie
  @namespace SimpleAuth.Stores
  @module simple-auth-cookie-store/stores/cookie
  @extends Stores.Base
*/
export default Base.extend({

  /**
    The domain to use for the cookie, e.g., "example.com", ".example.com"
    (includes all subdomains) or "subdomain.example.com". If not configured the
    cookie domain defaults to the domain the session was authneticated on.

    This value can be configured via
    [`SimpleAuth.Configuration.CookieStore#cookieDomain`](#SimpleAuth-Configuration-CookieStore-cookieDomain).

    @property cookieDomain
    @type String
    @default null
  */
  cookieDomain: null,

  /**
    The name of the cookie the store stores its data in.

    This value can be configured via
    [`SimpleAuth.Configuration.CookieStore#cookieName`](#SimpleAuth-Configuration-CookieStore-cookieName).

    @property cookieName
    @readOnly
    @type String
  */
  cookieName: 'ember_simple_auth:session',

  /**
    The expiration time in seconds to use for the cookie. A value of `null`
    will make the cookie a session cookie that expires when the browser is
    closed.

    This value can be configured via
    [`SimpleAuth.Configuration.CookieStore#cookieExpirationTime`](#SimpleAuth-Configuration-CookieStore-cookieExpirationTime).

    @property cookieExpirationTime
    @readOnly
    @type Integer
  */
  cookieExpirationTime: null,

  /**
    @property _secureCookies
    @private
  */
  _secureCookies: window.location.protocol === 'https:',

  /**
    @property _syncDataTimeout
    @private
  */
  _syncDataTimeout: null,

  /**
    @property _renewExpirationTimeout
    @private
  */
  _renewExpirationTimeout: null,

  /**
    @property pageVisibility
    @private
  */
  pageVisibility: null,

  /**
    @method init
    @private
  */
  init: function() {
    this.cookieName           = Configuration.cookieName;
    this.cookieExpirationTime = Configuration.cookieExpirationTime;
    this.cookieDomain         = Configuration.cookieDomain;
    this.pageVisibility       = this.pageVisibilityInit();
    this.syncData();
    this.renewExpiration();
  },

  /**
    @method readExpiration
    @private
  */
  readExpirationTime: function () {
    var value = document.cookie.match(new RegExp(this.cookieName + ':expiration_time=([^;]+)')) || [];
    return decodeURIComponent(value[1] || '');
  },

  /**
    Persists the `data` in session cookies.

    @method persist
    @param {Object} data The data to persist
  */
  persist: function(data) {
    data           = JSON.stringify(data || {});
    var cachedExpirationTime = !!this.readExpirationTime() ? new Date().getTime() + this.readExpirationTime() * 1000 : null;
    var expiration = !!this.cookieExpirationTime ? new Date().getTime() + this.cookieExpirationTime * 1000 : cachedExpirationTime;
    this.write(data, expiration);
    this._lastData = this.restore();
  },

  /**
    Restores all data currently saved in the cookie as a plain object.

    @method restore
    @return {Object} All data currently persisted in the cookie
  */
  restore: function() {
    var data = this.read();
    if (Ember.isEmpty(data)) {
      return {};
    } else {
      return JSON.parse(data);
    }
  },

  /**
    Clears the store by deleting all session cookies prefixed with the
    `cookieName` (see
    [`SimpleAuth.Stores.Cookie#cookieName`](#SimpleAuth-Stores-Cookie-cookieName)).

    @method clear
  */
  clear: function() {
    this.write(null, 0);
    this._lastData = {};
  },

  /**
    @method read
    @private
  */
  read: function() {
    var value = document.cookie.match(new RegExp(this.cookieName + '=([^;]+)')) || [];
    return decodeURIComponent(value[1] || '');
  },

  /**
    @method write
    @private
  */
  write: function(value, expiration) {
    var path    = '; path=/';
    var domain  = Ember.isEmpty(this.cookieDomain) ? '' : '; domain=' + this.cookieDomain;
    var expires = Ember.isEmpty(expiration) ? '' : '; expires=' + new Date(expiration).toUTCString();
    var secure  = !!this._secureCookies ? ';secure' : '';
    document.cookie = this.cookieName + '=' + encodeURIComponent(value) + domain + path + expires + secure;
    if(expiration !== null){ console.log('renewed to expire at : ' + new Date(expiration));
      document.cookie = this.cookieName + ':expiration_time=' + encodeURIComponent(this.cookieExpirationTime || this.readExpirationTime()) + domain + path + expires + secure;
    }
  },

  /**
    @method syncData
    @private
  */
  syncData: function() {
    var data = this.restore();
    if (!objectsAreEqual(data, this._lastData)) {
      this._lastData = data;
      this.trigger('sessionDataUpdated', data);
    }
    if (!Ember.testing) {
      Ember.run.cancel(this._syncDataTimeout);
      this._syncDataTimeout = Ember.run.later(this, this.syncData, 500);
    }
  },

  /**
    @method pageVisibilityInit
    @private
  */
  pageVisibilityInit: function(){
    var stateKey, eventKey, keys = {
      hidden: "visibilitychange",
      webkitHidden: "webkitvisibilitychange",
      mozHidden: "mozvisibilitychange",
      msHidden: "msvisibilitychange"
    };
    for (stateKey in keys) {
      if (stateKey in document) {
        eventKey = keys[stateKey];
        break;
      }
    }
    return function(c) {
      if (c) {document.addEventListener(eventKey, c);}
      return !document[stateKey];
    };
  },

  /**
    @method renew
    @private
  */
  renew: function(data) {
    data           = Ember.typeOf(data) === 'string' ? data : JSON.stringify(data || {});
    var cachedExpirationTime = !!this.readExpirationTime() ? new Date().getTime() + this.readExpirationTime() * 1000 : null;
    var expiration = !!this.cookieExpirationTime ? new Date().getTime() + this.cookieExpirationTime * 1000 : cachedExpirationTime;
    this.write(data, expiration);
  },

  /**
    @method renewExpiration
    @private
  */
  renewExpiration: function() {
    var data = this.restore();
    if (!Ember.isEmpty(data) && data !== {} && this.pageVisibility()) {
      this.renew(data);
    }
    Ember.run.cancel(this._renewExpirationTimeout);
    this._renewExpirationTimeout = Ember.run.later(this, this.renewExpiration, 60000);
  }
});
<commit_msg>clear debug code<commit_after>import Base from 'simple-auth/stores/base';
import objectsAreEqual from 'simple-auth/utils/objects-are-equal';
import Configuration from './../configuration';

/**
  Store that saves its data in a cookie.

  __In order to keep multiple tabs/windows of an application in sync, this
  store has to periodically (every 500ms) check the cookie__ for changes as
  there are no events that notify of changes in cookies. The recommended
  alternative is `Stores.LocalStorage` that also persistently stores data but
  instead of cookies relies on the `localStorage` API and does not need to poll
  for external changes.

  By default the cookie store will use a session cookie that expires and is
  deleted when the browser is closed. The cookie expiration period can be
  configured via setting
  [`Stores.Cooke#cookieExpirationTime`](#SimpleAuth-Stores-Cookie-cookieExpirationTime)
  though. This can also be used to implement "remember me" functionality that
  will either store the session persistently or in a session cookie depending
  whether the user opted in or not:

  ```js
  // app/controllers/login.js
  import LoginControllerMixin from 'simple-auth/mixins/login-controller-mixin';

  export default Ember.Controller.extend(LoginControllerMixin, {
    rememberMe: false,

    rememberMeChanged: function() {
      this.get('session.store').cookieExpirationTime = this.get('rememberMe') ? (14 * 24 * 60 * 60) : null;
    }.observes('rememberMe')
  });
  ```

  _The factory for this store is registered as
  `'simple-auth-session-store:cookie'` in Ember's container._

  @class Cookie
  @namespace SimpleAuth.Stores
  @module simple-auth-cookie-store/stores/cookie
  @extends Stores.Base
*/
export default Base.extend({

  /**
    The domain to use for the cookie, e.g., "example.com", ".example.com"
    (includes all subdomains) or "subdomain.example.com". If not configured the
    cookie domain defaults to the domain the session was authneticated on.

    This value can be configured via
    [`SimpleAuth.Configuration.CookieStore#cookieDomain`](#SimpleAuth-Configuration-CookieStore-cookieDomain).

    @property cookieDomain
    @type String
    @default null
  */
  cookieDomain: null,

  /**
    The name of the cookie the store stores its data in.

    This value can be configured via
    [`SimpleAuth.Configuration.CookieStore#cookieName`](#SimpleAuth-Configuration-CookieStore-cookieName).

    @property cookieName
    @readOnly
    @type String
  */
  cookieName: 'ember_simple_auth:session',

  /**
    The expiration time in seconds to use for the cookie. A value of `null`
    will make the cookie a session cookie that expires when the browser is
    closed.

    This value can be configured via
    [`SimpleAuth.Configuration.CookieStore#cookieExpirationTime`](#SimpleAuth-Configuration-CookieStore-cookieExpirationTime).

    @property cookieExpirationTime
    @readOnly
    @type Integer
  */
  cookieExpirationTime: null,

  /**
    @property _secureCookies
    @private
  */
  _secureCookies: window.location.protocol === 'https:',

  /**
    @property _syncDataTimeout
    @private
  */
  _syncDataTimeout: null,

  /**
    @property _renewExpirationTimeout
    @private
  */
  _renewExpirationTimeout: null,

  /**
    @property pageVisibility
    @private
  */
  pageVisibility: null,

  /**
    @method init
    @private
  */
  init: function() {
    this.cookieName           = Configuration.cookieName;
    this.cookieExpirationTime = Configuration.cookieExpirationTime;
    this.cookieDomain         = Configuration.cookieDomain;
    this.pageVisibility       = this.pageVisibilityInit();
    this.syncData();
    this.renewExpiration();
  },

  /**
    @method readExpiration
    @private
  */
  readExpirationTime: function () {
    var value = document.cookie.match(new RegExp(this.cookieName + ':expiration_time=([^;]+)')) || [];
    return decodeURIComponent(value[1] || '');
  },

  /**
    Persists the `data` in session cookies.

    @method persist
    @param {Object} data The data to persist
  */
  persist: function(data) {
    data           = JSON.stringify(data || {});
    var cachedExpirationTime = !!this.readExpirationTime() ? new Date().getTime() + this.readExpirationTime() * 1000 : null;
    var expiration = !!this.cookieExpirationTime ? new Date().getTime() + this.cookieExpirationTime * 1000 : cachedExpirationTime;
    this.write(data, expiration);
    this._lastData = this.restore();
  },

  /**
    Restores all data currently saved in the cookie as a plain object.

    @method restore
    @return {Object} All data currently persisted in the cookie
  */
  restore: function() {
    var data = this.read();
    if (Ember.isEmpty(data)) {
      return {};
    } else {
      return JSON.parse(data);
    }
  },

  /**
    Clears the store by deleting all session cookies prefixed with the
    `cookieName` (see
    [`SimpleAuth.Stores.Cookie#cookieName`](#SimpleAuth-Stores-Cookie-cookieName)).

    @method clear
  */
  clear: function() {
    this.write(null, 0);
    this._lastData = {};
  },

  /**
    @method read
    @private
  */
  read: function() {
    var value = document.cookie.match(new RegExp(this.cookieName + '=([^;]+)')) || [];
    return decodeURIComponent(value[1] || '');
  },

  /**
    @method write
    @private
  */
  write: function(value, expiration) {
    var path    = '; path=/';
    var domain  = Ember.isEmpty(this.cookieDomain) ? '' : '; domain=' + this.cookieDomain;
    var expires = Ember.isEmpty(expiration) ? '' : '; expires=' + new Date(expiration).toUTCString();
    var secure  = !!this._secureCookies ? ';secure' : '';
    document.cookie = this.cookieName + '=' + encodeURIComponent(value) + domain + path + expires + secure;
    if(expiration !== null){
      document.cookie = this.cookieName + ':expiration_time=' + encodeURIComponent(this.cookieExpirationTime || this.readExpirationTime()) + domain + path + expires + secure;
    }
  },

  /**
    @method syncData
    @private
  */
  syncData: function() {
    var data = this.restore();
    if (!objectsAreEqual(data, this._lastData)) {
      this._lastData = data;
      this.trigger('sessionDataUpdated', data);
    }
    if (!Ember.testing) {
      Ember.run.cancel(this._syncDataTimeout);
      this._syncDataTimeout = Ember.run.later(this, this.syncData, 500);
    }
  },

  /**
    @method pageVisibilityInit
    @private
  */
  pageVisibilityInit: function(){
    var stateKey, eventKey, keys = {
      hidden: "visibilitychange",
      webkitHidden: "webkitvisibilitychange",
      mozHidden: "mozvisibilitychange",
      msHidden: "msvisibilitychange"
    };
    for (stateKey in keys) {
      if (stateKey in document) {
        eventKey = keys[stateKey];
        break;
      }
    }
    return function(c) {
      if (c) {document.addEventListener(eventKey, c);}
      return !document[stateKey];
    };
  },

  /**
    @method renew
    @private
  */
  renew: function(data) {
    data           = Ember.typeOf(data) === 'string' ? data : JSON.stringify(data || {});
    var cachedExpirationTime = !!this.readExpirationTime() ? new Date().getTime() + this.readExpirationTime() * 1000 : null;
    var expiration = !!this.cookieExpirationTime ? new Date().getTime() + this.cookieExpirationTime * 1000 : cachedExpirationTime;
    this.write(data, expiration);
  },

  /**
    @method renewExpiration
    @private
  */
  renewExpiration: function() {
    var data = this.restore();
    if (!Ember.isEmpty(data) && data !== {} && this.pageVisibility()) {
      this.renew(data);
    }
    Ember.run.cancel(this._renewExpirationTimeout);
    this._renewExpirationTimeout = Ember.run.later(this, this.renewExpiration, 60000);
  }
});
<|endoftext|>


<commit_before>import {
  compose,
  lifecycle
} from 'recompose';
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';

export const REMOVE_WIDGET = 'widget-base/REMOVE_WIDGET';
export function removeWidget() {
  return {
    type: REMOVE_WIDGET
  };
}

export default function withRemoveWidget() {
  return (BaseComponent) => compose(
    connect(
      (state) => state,
      (dispatch) => bindActionCreators({
        removeWidget
      }, dispatch)
    ),
    lifecycle({
      componentWillUnmount() {
        this.props.removeWidget();
      }
    })
  )(BaseComponent);
}
<commit_msg>fix(spark-widget-base): Do not remove clear on unmount<commit_after>import {compose} from 'recompose';
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';

export const REMOVE_WIDGET = 'widget-base/REMOVE_WIDGET';
export function removeWidget() {
  return {
    type: REMOVE_WIDGET
  };
}

export default function withRemoveWidget() {
  return (BaseComponent) => compose(
    connect(
      null,
      (dispatch) => bindActionCreators({
        removeWidget
      }, dispatch)
    )
  )(BaseComponent);
}
<|endoftext|>


<commit_before>window.Rendxx = window.Rendxx || {};
window.Rendxx.Game = window.Rendxx.Game || {};
window.Rendxx.Game.Ghost = window.Rendxx.Game.Ghost || {};
window.Rendxx.Game.Ghost.System = window.Rendxx.Game.Ghost.System || {};

/**
 * InterAction manager, use to send/receive command between players
 */
(function (SYSTEM) {
    var Data = SYSTEM.Data;
    var _Data = {
        actionType: {
            'move': 'm',
            'tap_move': 'tm',

            'tap_1': 't1',
            'press_1': 'p1',
            'release_1': 'r1',

            'tap_2': 't2',
            'press_2': 'p2',
            'release_2': 'r2',
        }
    };
    var UserInput = function (entity) {
        // data ----------------------------------------------------------
        var that = this,
            characterFunc = {};

        // callback ------------------------------------------------------

        // public method -------------------------------------------------
        this.action = function (clientId, dat) {
            if (characterFunc[clientId].hasOwnProperty(dat['actionType'])) characterFunc[clientId][dat['actionType']](dat);
        };

        // bind character function to user input
        this.reset = function (characters, index2Id) {
            characterFunc = {};
            for (var i = 0; i < characters.length; i++) {
                var c = characters[i];
                var func = {};
                characterFunc[index2Id[i]] = func;
                if (c instanceof SYSTEM.Character.Survivor.Normal) {
                    // survivor
                    _setupSurvivor(func, c);
                } else if (c instanceof SYSTEM.Character.Ghost.Mary) {
                    // ghost.mary
                    _setupGhostMary(func, c);
                } else if (c instanceof SYSTEM.Character.Ghost.Specter) {
                    // ghost.specter
                    _setupGhostSpecter(func, c);
                }
            }
        };

        // private method ------------------------------------------------
        var _setupSurvivor = function (func, c) {
            func[_Data.actionType.move] = function (dat) { c.move(dat['direction'], dat['directionHead'], dat['rush'], dat['stay'], dat['headFollow']); };
            func[_Data.actionType.tap_move] = function (dat) { c.interaction(); };
            func[_Data.actionType.press_1] = function (dat) { c.longInteraction(); };
            func[_Data.actionType.release_1] = function (dat) { c.cancelLongInteraction(); };
        };

        var _setupGhostMary = function (func, c) {
            func[_Data.actionType.move] = function (dat) { c.move(dat['direction'], dat['directionHead'], dat['rush'], dat['stay'], dat['headFollow']); };
            func[_Data.actionType.tap_move] = function (dat) { c.interaction(); };
            func[_Data.actionType.tap_1] = function (dat) { c.crazy(); };
            func[_Data.actionType.press_1] = function (dat) { c.teleportStart(); };
            func[_Data.actionType.release_1] = function (dat) { c.teleportEnd(); };
        };

        var _setupGhostSpecter = function (func, c) {
            func[_Data.actionType.move] = function (dat) { c.move(dat['direction'], dat['directionHead'], dat['rush'], dat['stay'], dat['headFollow']); };
            func[_Data.actionType.tap_move] = function (dat) { c.observe(); };
            func[_Data.actionType.tap_1] = function (dat) { c.kill(); };
        };

        var _init = function () {
        };
        _init();
    };

    SYSTEM.UserInput = UserInput
})(window.Rendxx.Game.Ghost.System);<commit_msg>Add butcher user input<commit_after>window.Rendxx = window.Rendxx || {};
window.Rendxx.Game = window.Rendxx.Game || {};
window.Rendxx.Game.Ghost = window.Rendxx.Game.Ghost || {};
window.Rendxx.Game.Ghost.System = window.Rendxx.Game.Ghost.System || {};

/**
 * InterAction manager, use to send/receive command between players
 */
(function (SYSTEM) {
    var Data = SYSTEM.Data;
    var _Data = {
        actionType: {
            'move': 'm',
            'tap_move': 'tm',

            'tap_1': 't1',
            'press_1': 'p1',
            'release_1': 'r1',

            'tap_2': 't2',
            'press_2': 'p2',
            'release_2': 'r2',
        }
    };
    var UserInput = function (entity) {
        // data ----------------------------------------------------------
        var that = this,
            characterFunc = {};

        // callback ------------------------------------------------------

        // public method -------------------------------------------------
        this.action = function (clientId, dat) {
            if (characterFunc[clientId].hasOwnProperty(dat['actionType'])) characterFunc[clientId][dat['actionType']](dat);
        };

        // bind character function to user input
        this.reset = function (characters, index2Id) {
            characterFunc = {};
            for (var i = 0; i < characters.length; i++) {
                var c = characters[i];
                var func = {};
                characterFunc[index2Id[i]] = func;
                if (c instanceof SYSTEM.Character.Survivor.Normal) {
                    // survivor
                    _setupSurvivor(func, c);
                } else if (c instanceof SYSTEM.Character.Ghost.Mary) {
                    // ghost.mary
                    _setupGhostMary(func, c);
                } else if (c instanceof SYSTEM.Character.Ghost.Specter) {
                    // ghost.specter
                    _setupGhostSpecter(func, c);
                } else if (c instanceof SYSTEM.Character.Ghost.Butcher) {
                    // ghost.specter
                    _setupGhostButcher(func, c);
                }
            }
        };

        // private method ------------------------------------------------
        var _setupSurvivor = function (func, c) {
            func[_Data.actionType.move] = function (dat) { c.move(dat['direction'], dat['directionHead'], dat['rush'], dat['stay'], dat['headFollow']); };
            func[_Data.actionType.tap_move] = function (dat) { c.interaction(); };
            func[_Data.actionType.press_1] = function (dat) { c.longInteraction(); };
            func[_Data.actionType.release_1] = function (dat) { c.cancelLongInteraction(); };
        };

        var _setupGhostMary = function (func, c) {
            func[_Data.actionType.move] = function (dat) { c.move(dat['direction'], dat['directionHead'], dat['rush'], dat['stay'], dat['headFollow']); };
            func[_Data.actionType.tap_move] = function (dat) { c.interaction(); };
            func[_Data.actionType.tap_1] = function (dat) { c.crazy(); };
            func[_Data.actionType.press_1] = function (dat) { c.teleportStart(); };
            func[_Data.actionType.release_1] = function (dat) { c.teleportEnd(); };
        };

        var _setupGhostSpecter = function (func, c) {
            func[_Data.actionType.move] = function (dat) { c.move(dat['direction'], dat['directionHead'], dat['rush'], dat['stay'], dat['headFollow']); };
            func[_Data.actionType.tap_move] = function (dat) { c.observe(); };
            func[_Data.actionType.tap_1] = function (dat) { c.kill(); };
        };

        var _setupGhostButcher = function (func, c) {
            func[_Data.actionType.move] = function (dat) { c.move(dat['direction'], dat['directionHead'], dat['rush'], dat['stay'], dat['headFollow']); };
            func[_Data.actionType.tap_move] = function (dat) { c.observe(); };
            func[_Data.actionType.tap_1] = function (dat) { c.kill(); };
        };

        var _init = function () {
        };
        _init();
    };

    SYSTEM.UserInput = UserInput
})(window.Rendxx.Game.Ghost.System);<|endoftext|>


<commit_before>var debug = false;
var log = function(m) { if (debug && console && console.log) console.log(m); }
var app, timeout, appId;
var providers = [];
var manuallyClosed = false;
var retryTime = 1000;

$(document).ready(
    function() {
        // any mouse activity resets it
        $(document).mousemove( function() {
            retryTime = 1000;
        } );

        app = window.location.hash.substring(1) || "contacts";

        $('.app-select').click(function() {
            $('.app-select').toggleClass('on');
            $('.children').toggle();
        });

        $('.app-link').click(function() {
            app = $(this).attr('id');
            window.location.hash = app;
            renderApp();
            return false;
        });

        // open service drawer button
        $('.services-box').click(function() {
            expandServices();
        });

        // close service drawer button
        $('#service-closer').click(function() {
            if ($('.blur:visible').length === 0) {
                manuallyClosed = true;
                $.post('closed', function(data) { log("success"); });
                closeServices();
            }
        });

        // service buttons
        $('#service-selector').delegate('.provider-link', 'click', function() {
            if ($(this).hasClass('disabled')) return false;
            accountPopup($(this));
            return false;
        });

        // search box
        $('#nav-search').submit(function() {
            var inputText = $("#nav-search .search").val();
            $("#nav-search .search").val("");
            window.location.hash = "search";
            $('.selected').removeClass('selected');
            $("#appFrame")[0].contentWindow.location.replace("/Me/searchapp/search?type=&searchterm="+inputText);
            return false;
        });

        // disable pass through click events when an area is blurred
        $('.blur').click(function() {
            return false;
        });

        $(".app-link[title]").tooltip({
            position:"bottom center",
            predelay:750,
            onBeforeShow: function(ev) {
                var id = this.getTrigger().attr("id");
                // Chop off the s!
                id = id.substring(0, id.length - 1);
                var tip = $('.' + id + 'sTotalCount').text() + '

';
                if (allCounts[id] && allCounts[id].lastUpdate) {
                    var timeDiff = Date.now() - allCounts[id].lastUpdate;
                    if (timeDiff < 60000) {
                        tip += 'last updated less than a minute ago';
                    } else if (timeDiff < 3600000) {
                        tip += 'last updated ' + Math.floor(timeDiff / 60000) + ' minutes ago';
                    } else if (timeDiff < 43200000) {
                        tip += 'last updated over an hour ago';
                    } else if (timeDiff < 43800000) {
                        tip += 'last updated ' + Math.floor(timeDiff / 3600000) + ' hours ago';
                    } else {
                        var d = new Date;
                        d.setTime(allCounts[id].lastUpdate);
                        log(allCounts);
                        tip += 'last updated ' + d.toString();
                    }
                    tip += '
';
                }
                this.getTip().html('
' + tip + '
');
            }
        });

        renderApp();

        $(window).resize(resizeFrame);
        resizeFrame();
    }
);

/*
 * SyncletPoll
 */
var SyncletPoll = (
    function () {
        var SyncletPoll = function () {
            var t = this;
            t.uri = "/synclets";
            t.repoll = true;
            t.installed = {};

            var app = {};

            t.updateState = function(provider, app) {
                var b =  {
                    "$el": $("#"+provider+"connect")
                };

                if (typeof(t.installed[provider]) != "undefined") {
                    b = t.installed[provider];
                } else {
                    t.installed[provider] = b;
                    b.$el.find('a').addClass("disabled");
                }

                if (app.finishedOnce) {
                    b.$el.find('.checkmark').show();
                }

                 if (b.state == "running" || b.state == "processing data") {
                    if (typeof(b.spinner) == "undefined" && !(b.$el.find('.checkmark').is(':visible'))) {
                        var target = b.$el.find(".spinner")[0];
                        b.$el.find('a').addClass("disabled");
                        b.spinner = new Spinner(spinnerOpts).spin(target);
                    } else if (!(b.$el.find('.checkmark').is(':visible'))) {
                        b.spinner.spin();
                    }
                } else if (b.state == "waiting") {
                    if (b.spinner) b.spinner.stop();
                    b.$el.find('.checkmark').show();
                }

                b.lastState = b.state;
                t.installed[provider] = b;
            };

            t.handleResponse = function(data, err, resp) {
                if(retryTime < 10000) retryTime += 500;
                for (app in data.installed) {
                    app = data.installed[app];

                    if (providers.indexOf(app.provider) != -1) {
                        // update app button with "pending" gfx
                        t.updateState(app.provider, app);
                    }
                }

                if (t.repoll) t.timeout = setTimeout(t.query, retryTime);
            };

            t.query = function() {
                var url = t.uri;
                $.ajax({
                           url: url,
                           dataType: 'json',
                           success: t.handleResponse,
                           error: function(e) {
                               // assume it will become available later
                               t.timeout = setTimeout(t.query, 3000);
                           }
                       });
            };

            t.halt = function() {
                t.repoll = false;
                clearTimeout(t.timeout);
            };

            // init
            t.query();
        };

        return function () {
            return new SyncletPoll();
        };

    })();

function drawServices() {
    $.getJSON('/available?handle=' + appId, function(data) {
        $.getJSON('/synclets', function(synclets) {
            $('.service:not(.template)').remove();
            providers = [];
            var syncletsToRender = [];
            for (var i in data.uses) {
                for (var j = 0; j < synclets.available.length; j++) {
                    if (synclets.available[j].provider === data.uses[i]) {
                        if(synclets.available[j].authurl) {
                            providers.push(data.uses[i]);
                            if (typeof(synclets.installed[data.uses[i]]) != "undefined") {
                                syncletsToRender.push(synclets.available[j]);
                            } else {
                                syncletsToRender.unshift(synclets.available[j]);
                            }
                        }
                    }
                }
            }
            for (var i = 0; i < syncletsToRender.length; i++) {
                drawService(syncletsToRender[i]);
            }
            if (!window.syncletPoll) {
                window.syncletPoll = new SyncletPoll(providers);
            } else {
                window.syncletPoll.halt();
                delete window.syncletPoll;
                window.syncletPoll = new SyncletPoll(providers);
            }
        });
    });
}

function drawService(synclet) {
    var newService = $('.service.template').clone();
    newService.find('.provider-icon').attr('src', 'img/icons/' + synclet.provider + '.png').attr('title', synclet.info);
    newService.find('.provider-link').attr('href', synclet.authurl).data('provider', synclet.provider);
    newService.find('.provider-name').text(synclet.provider);
    newService.removeClass('template');
    newService.attr('id', synclet.provider + 'connect');
    $('#service-selector').append(newService);
};

// this needs some cleanup to actually use the proper height + widths
function accountPopup (elem) {
    var width = 620;
    var height = 400;
    var oauthPopupSizes = {foursquare: {height: 540,  width: 960},
                 github: {height: 1000, width: 1000},
                 twitter: {width: 630, height: 500},
                 tumblr: {width: 630, height: 500},
                 facebook: {width: 980, height: 705},
                 flickr: {width: 1000, height: 877}
                };
    if (oauthPopupSizes[elem.data('provider')]) {
        width = oauthPopupSizes[elem.data('provider')].width;
        height = oauthPopupSizes[elem.data('provider')].height;
    }
    var popup = window.open(elem.attr('href'), "account", "width=" + width + ",height=" + height + ",status=no,scrollbars=no,resizable=no");
    popup.focus();
}

function renderApp(fragment) {
    var ready = false;
    if (timeout) clearTimeout(timeout);
    $('.selected').removeClass('selected');
    $("#" + app).addClass('selected');
    $.getJSON('apps', function(data) {
        ready = false;
        if (!data[app]) return;
        appId = data[app].id;
        drawServices();
        (function poll (data) {
            $.getJSON("/Me/" + app + "/state", function(state) {
                ready = state.count > 0;
                if (ready) {
                    // log('clearing timeout');
                    var needReload = false;
                    if (data[app].url == $("#appFrame")[0].contentWindow.location) needReload = true;
                    $("#appFrame")[0].contentWindow.location.replace(data[app].url + (fragment?("#"+fragment):""));
                    if (needReload) {
                        console.log("Needs a reload");
                        $("#appFrame")[0].contentDocument.location.reload(true);
                    }
                    clearTimeout(timeout);
                }
                else {
                    if (!manuallyClosed && $('#services').height() === 0) expandServices();
                    var currentLocation = $("#appFrame")[0].contentWindow.location;
                    var newLocation = data[app].url + "notready.html";
                    if (currentLocation.toString() !== newLocation)
                        currentLocation.replace(newLocation);
                    clearTimeout(timeout);
                    timeout = setTimeout(function() {poll(data);}, 1000);
                    //log(timeout);
                }
            });
        })(data);
    });
};

function expandServices() {
    $('.services-box-container').hide();
    $('#appFrame').animate({height: $('#appFrame').height() - 110}, {duration: 200, queue: false});
    $('#services').animate({height: "110px"}, {duration: 200});
}

function resizeFrame() {
    $('#appFrame').height($(window).height() - $('#services').height() - $('.header').height() - 6);
    $("#appFrame").width($(window).width());
}
<commit_msg>no more working on this right now, I need other eyes<commit_after>var debug = false;
var log = function(m) { if (debug && console && console.log) console.log(m); }
var app, timeout, appId;
var providers = [];
var manuallyClosed = false;
var retryTime = 1000;
var ready = false;

$(document).ready(
    function() {
        // any mouse activity resets it
        $(document).mousemove( function() {
            retryTime = 1000;
        } );

        app = window.location.hash.substring(1) || "contacts";

        $('.app-select').click(function() {
            $('.app-select').toggleClass('on');
            $('.children').toggle();
        });

        $('.app-link').click(function() {
            app = $(this).attr('id');
            window.location.hash = app;
            renderApp();
            return false;
        });

        // open service drawer button
        $('.services-box').click(function() {
            expandServices();
        });

        // close service drawer button
        $('#service-closer').click(function() {
            if ($('.blur:visible').length === 0) {
                manuallyClosed = true;
                $.post('closed', function(data) { log("success"); });
                closeServices();
            }
        });

        // service buttons
        $('#service-selector').delegate('.provider-link', 'click', function() {
            if ($(this).hasClass('disabled')) return false;
            accountPopup($(this));
            return false;
        });

        // search box
        $('#nav-search').submit(function() {
            var inputText = $("#nav-search .search").val();
            $("#nav-search .search").val("");
            window.location.hash = "search";
            $('.selected').removeClass('selected');
            $("#appFrame")[0].contentWindow.location.replace("/Me/searchapp/search?type=&searchterm="+inputText);
            return false;
        });

        // disable pass through click events when an area is blurred
        $('.blur').click(function() {
            return false;
        });

        $(".app-link[title]").tooltip({
            position:"bottom center",
            predelay:750,
            onBeforeShow: function(ev) {
                var id = this.getTrigger().attr("id");
                // Chop off the s!
                id = id.substring(0, id.length - 1);
                var tip = $('.' + id + 'sTotalCount').text() + '

';
                if (allCounts[id] && allCounts[id].lastUpdate) {
                    var timeDiff = Date.now() - allCounts[id].lastUpdate;
                    if (timeDiff < 60000) {
                        tip += 'last updated less than a minute ago';
                    } else if (timeDiff < 3600000) {
                        tip += 'last updated ' + Math.floor(timeDiff / 60000) + ' minutes ago';
                    } else if (timeDiff < 43200000) {
                        tip += 'last updated over an hour ago';
                    } else if (timeDiff < 43800000) {
                        tip += 'last updated ' + Math.floor(timeDiff / 3600000) + ' hours ago';
                    } else {
                        var d = new Date;
                        d.setTime(allCounts[id].lastUpdate);
                        log(allCounts);
                        tip += 'last updated ' + d.toString();
                    }
                    tip += '
';
                }
                this.getTip().html('
' + tip + '
');
            }
        });

        renderApp();

        $(window).resize(resizeFrame);
        resizeFrame();
    }
);

/*
 * SyncletPoll
 */
var SyncletPoll = (
    function () {
        var SyncletPoll = function () {
            var t = this;
            t.uri = "/synclets";
            t.repoll = true;
            t.installed = {};

            var app = {};

            t.updateState = function(provider, app) {
                var b =  {
                    "$el": $("#"+provider+"connect")
                };

                if (typeof(t.installed[provider]) != "undefined") {
                    b = t.installed[provider];
                } else {
                    t.installed[provider] = b;
                    b.$el.find('a').addClass("disabled");
                }

                if (app.finishedOnce) {
                    b.$el.find('.checkmark').show();
                }
            };

            t.handleResponse = function(data, err, resp) {
                if(retryTime < 10000) retryTime += 500;
                var hasProps = false;
                globalvar = data.installed;
                for (app in data.installed) {
                    hasProps = true;
                    if (window.guidedSetup) window.guidedSetup.servicesAdded();
                    app = data.installed[app];

                    if (providers.indexOf(app.provider) != -1) {
                        // update app button with "pending" gfx
                        t.updateState(app.provider, app);
                    }
                }
                if (!hasProps && !window.guidedSetup) {
                    window.guidedSetup = new GuidedSetup();
                }
                if (ready === false && hasProps && $('#services').height() === 0) expandServices();

                if (t.repoll) t.timeout = setTimeout(t.query, retryTime);
            };

            t.query = function() {
                var url = t.uri;
                $.ajax({
                           url: url,
                           dataType: 'json',
                           success: t.handleResponse,
                           error: function(e) {
                               // assume it will become available later
                               t.timeout = setTimeout(t.query, 3000);
                           }
                       });
            };

            t.halt = function() {
                t.repoll = false;
                clearTimeout(t.timeout);
            };

            // init
            t.query();
        };

        return function () {
            return new SyncletPoll();
        };

    })();

function drawServices() {
    $.getJSON('/available?handle=' + appId, function(data) {
        $.getJSON('/synclets', function(synclets) {
            $('.service:not(.template)').remove();
            providers = [];
            var syncletsToRender = [];
            for (var i in data.uses) {
                for (var j = 0; j < synclets.available.length; j++) {
                    if (synclets.available[j].provider === data.uses[i]) {
                        if(synclets.available[j].authurl) {
                            providers.push(data.uses[i]);
                            if (typeof(synclets.installed[data.uses[i]]) != "undefined") {
                                syncletsToRender.push(synclets.available[j]);
                            } else {
                                syncletsToRender.unshift(synclets.available[j]);
                            }
                        }
                    }
                }
            }
            for (var i = 0; i < syncletsToRender.length; i++) {
                drawService(syncletsToRender[i]);
            }
            if (!window.syncletPoll) {
                window.syncletPoll = new SyncletPoll(providers);
            } else {
                window.syncletPoll.halt();
                delete window.syncletPoll;
                window.syncletPoll = new SyncletPoll(providers);
            }
        });
    });
}

function drawService(synclet) {
    var newService = $('.service.template').clone();
    newService.find('.provider-icon').attr('src', 'img/icons/' + synclet.provider + '.png').attr('title', synclet.info);
    newService.find('.provider-link').attr('href', synclet.authurl).data('provider', synclet.provider);
    newService.find('.provider-name').text(synclet.provider);
    newService.removeClass('template');
    newService.attr('id', synclet.provider + 'connect');
    $('#service-selector').append(newService);
};

// this needs some cleanup to actually use the proper height + widths
function accountPopup (elem) {
    var width = 620;
    var height = 400;
    var oauthPopupSizes = {foursquare: {height: 540,  width: 960},
                 github: {height: 1000, width: 1000},
                 twitter: {width: 630, height: 500},
                 tumblr: {width: 630, height: 500},
                 facebook: {width: 980, height: 705},
                 flickr: {width: 1000, height: 877}
                };
    if (oauthPopupSizes[elem.data('provider')]) {
        width = oauthPopupSizes[elem.data('provider')].width;
        height = oauthPopupSizes[elem.data('provider')].height;
    }
    var popup = window.open(elem.attr('href'), "account", "width=" + width + ",height=" + height + ",status=no,scrollbars=no,resizable=no");
    popup.focus();
}

function renderApp(fragment) {
    var ready = false;
    if (timeout) clearTimeout(timeout);
    $('.selected').removeClass('selected');
    $("#" + app).addClass('selected');
    $.getJSON('apps', function(data) {
        ready = false;
        if (!data[app]) return;
        appId = data[app].id;
        drawServices();
        (function poll (data) {
            $.getJSON("/Me/" + app + "/state", function(state) {
                ready = state.count > 0;
                if (ready) {
                    // log('clearing timeout');
                    var needReload = false;
                    if (data[app].url == $("#appFrame")[0].contentWindow.location) needReload = true;
                    $("#appFrame")[0].contentWindow.location.replace(data[app].url + (fragment?("#"+fragment):""));
                    if (needReload) {
                        console.log("Needs a reload");
                        $("#appFrame")[0].contentDocument.location.reload(true);
                    }
                    clearTimeout(timeout);
                    if (manuallyClosed) closeServices();
                }
                else {
                    var currentLocation = $("#appFrame")[0].contentWindow.location;
                    var newLocation = data[app].url + "notready.html";
                    if (currentLocation.toString() !== newLocation)
                        currentLocation.replace(newLocation);
                    clearTimeout(timeout);
                    timeout = setTimeout(function() {poll(data);}, 1000);
                    log(timeout);
                }
            });
        })(data);
    });
};

function expandServices() {
    $('.services-box-container').hide();
    $('#appFrame').animate({height: $('#appFrame').height() - 110}, {duration: 200, queue: false});
    $('#services').animate({height: "110px"}, {duration: 200});
}

function resizeFrame() {
    $('#appFrame').height($(window).height() - $('#services').height() - $('.header').height() - 6);
    $("#appFrame").width($(window).width());
}

function drawGuidedSetup() {
    if (guidedSetupActive) return;
    guidedSetupActive = true;
    $('.blur').show();
}

function closeServices() {
    $('#appFrame').animate({height: $('#appFrame').height() + 110}, {duration: 200, queue: false});
        $('#services').animate({height: "0px"}, {duration: 200, queue: false, complete:function() {
            $('.services-box-container').show();
            resizeFrame();
        }
    });
}

/*
 * GuidedSetup
 */
var GuidedSetup = (
    function () {
        var GuidedSetup = function () {
            var t = this;
            var page = 0;
            var text = {};
            t.synced = false;
            text.header = ['Welcome!', 'Get Started.', 'Explore...'];
            text.forward = ['NEXT', 'NEXT', 'DONE'];
            text.body = [];
            text.body[0] = "
This helps you pull all your stuff together from around the web.
" +
                           "

";
            text.body[1] = "
To get started, connect some services you use.
" +
                           "

";
            text.body[2] = "
Now that you've got some services connected, you can got check out the different views!
" +
                           "
Photos - See all your photos from around the web in one place.
" +
                           "
People - See everyone you are connected to in one place.
" +
                           "
Links - Search for and discover all the links people are sharing with you.
";

            t.drawGuidedSetup = function() {
                $('.blur').show();
                $('.close-box').click(function() {
                    $('.blur').hide();
                });
                $('.forward').click(t.moveForward);
                $(document).keydown(function(e) {
                    if (e.keyCode === 27) {
                        $('.blur').hide();
                    }
                });

                t.updateText();
            };

            t.moveForward = function() {
                log('moving forward!');
                log(page);
                log(t.synced);
                if (page === 0 && t.synced === false) {
                    $('.forward').addClass('disabled');
                    $('.forward').attr('title', 'You must authorize a service to continue!');
                    $('.forward-buttton-text').attr('title', 'You must authorize a service to continue!');
                    expandServices();
                }
                if (page === 1 && t.synced === false) {
                    return;
                }
                if (page === 2) {
                    return $('.blur').hide();
                }
                page++;
                t.updateBlurs();
                t.updateText();
            }

            t.servicesAdded = function() {
                log('added services!');
                if (t.synced) return;
                t.synced = true;
                $('.forward').removeClass('disabled');
                $('.forward').attr('title', '');
                $('.forward-button-text').attr('title', '');
            }

            t.updateBlurs = function() {
                $('.blur').show();
                if (page === 1) {
                    $('#services .blur').hide();
                } else if (page === 2) {
                    $('.header .blur').hide();
                }
            }

            t.updateText = function() {
                $('.header-text').animate({opacity: 0}, {duration: 200, queue: false});
                $('.forward-button-text').animate({opacity: 0}, {duration: 200, queue: false});
                $('.lightbox .body').animate({opacity: 0}, {duration: 200, queue: false, complete:function() {
                    $('.header-text').text(text.header[page]);
                    $('.forward-button-text').text(text.forward[page]);
                    $('.lightbox .body').html(text.body[page]);
                    $('.header-text').animate({opacity: 1}, {duration: 200, queue: false});
                    $('.forward-button-text').animate({opacity: 1}, {duration: 200, queue: false});
                    $('.lightbox .body').animate({opacity: 1}, {duration: 200, queue: false});
                }});

           }

            t.drawGuidedSetup();
        };

        return function () {
            return new GuidedSetup();
        };

    })();
<|endoftext|>


<commit_before>//===============================================================
//==========================  UI ================================
//===============================================================

  // rende i select meravigliosi colorati e hipster
  $("select").selectpicker({style: 'btn-hg btn-primary', menuStyle: 'dropdown-inverse'});
    $("button.dropdown-toggle").css({
        'background':'#404040'
    });

  // switch costo abitazione (conosciuto o no)
  $('#checkbox-abitazione').change(function () {
    $('#costo-sconosciuto').fadeToggle();
    $('#costo-conosciuto').fadeToggle();
  });

  //aggiungi nuova auto
  $('#bottone-aggiungi-auto').click(function () {
    $('#aggiungi-auto').fadeToggle();
  });
  //aggiungi nuovo mezzo
  $('#bottone-aggiungi-mezzo').click(function () {
    $('#aggiungi-mezzo').fadeToggle();
  });

  $("#menu-trasporti").click(function() {
    show_side_menu("#trasporti");
  });

  $("#menu-abitazione").click(function() {
    show_side_menu("#abitazione");
  });

  $("#menu-spostamenti").click(function() {
    show_side_menu("#spostamenti");
  });

//===============================================================
//========================= UTILITY =============================
//===============================================================

function load_partial(page, container_id, on_complate) {
  $.get(page, function (data){
    $(container_id).html(data).ready(from_famiglia());
  });
}

function increment_inpunt_value (){
  $(".tagsinput-add").on("click", function(event) {
    var button = $(this);
    var input = button.parent().find('input');
    var old_value = input.val();

    if (old_value == "") {
      old_value = 0;
    };
    //Incremento il valore e salvo
    input.val(++old_value);
  });
}

function decrement_input_value (){
  $(".tagsinput-remove").on("click", function(event) {
    var button = $(this);
    var input = button.parent().find('input');
    var old_value = input.val();

    if (old_value == "") {
      old_value = 0;
    };
    if (--old_value >= 0) {
      //Incremento il valore e salvo
      input.val(old_value);
    };
  });
}

//===============================================================
//======================= NEW SESSION ===========================
//===============================================================
$('#new-session').click(function () {
  load_from_famiglia();
});

$("#welcome-avanti").click(function() {
  load_from_famiglia();
  $("#welcome").hide();
});

//===============================================================
//====================== FROM FAMIGLIA ==========================
//===============================================================

$("#menu-famiglia-button").click(function() {
  load_from_famiglia();
});

function load_from_famiglia() {
  load_partial("partials/famiglia.html", "#form-container", from_famiglia());
}

function from_famiglia(){
  //Collego i bottono +,-
  increment_inpunt_value();
  decrement_input_value();

  $("#famiglia-avanti").click(function() {
    var data = {};
    $.each($('#famiglia-caller').serializeArray(), function (i, el){
      data[el.name] = el.value;
    });
    user_new_data.famiglia = data;
  });
}

<commit_msg>Quando si fa click su new session appare il menu a lato<commit_after>//===============================================================
//==========================  UI ================================
//===============================================================

  // rende i select meravigliosi colorati e hipster
  $("select").selectpicker({style: 'btn-hg btn-primary', menuStyle: 'dropdown-inverse'});
    $("button.dropdown-toggle").css({
        'background':'#404040'
    });

  // switch costo abitazione (conosciuto o no)
  $('#checkbox-abitazione').change(function () {
    $('#costo-sconosciuto').fadeToggle();
    $('#costo-conosciuto').fadeToggle();
  });

  //aggiungi nuova auto
  $('#bottone-aggiungi-auto').click(function () {
    $('#aggiungi-auto').fadeToggle();
  });
  //aggiungi nuovo mezzo
  $('#bottone-aggiungi-mezzo').click(function () {
    $('#aggiungi-mezzo').fadeToggle();
  });

  $("#menu-trasporti").click(function() {
    show_side_menu("#trasporti");
  });

  $("#menu-abitazione").click(function() {
    show_side_menu("#abitazione");
  });

  $("#menu-spostamenti").click(function() {
    show_side_menu("#spostamenti");
  });

//===============================================================
//========================= UTILITY =============================
//===============================================================

function load_partial(page, container_id, on_complate) {
  $.get(page, function (data){
    $(container_id).html(data).ready(from_famiglia());
  });
}

function increment_inpunt_value (){
  $(".tagsinput-add").on("click", function(event) {
    var button = $(this);
    var input = button.parent().find('input');
    var old_value = input.val();

    if (old_value == "") {
      old_value = 0;
    };
    //Incremento il valore e salvo
    input.val(++old_value);
  });
}

function decrement_input_value (){
  $(".tagsinput-remove").on("click", function(event) {
    var button = $(this);
    var input = button.parent().find('input');
    var old_value = input.val();

    if (old_value == "") {
      old_value = 0;
    };
    if (--old_value >= 0) {
      //Incremento il valore e salvo
      input.val(old_value);
    };
  });
}

//===============================================================
//======================= NEW SESSION ===========================
//===============================================================
$('#new-session').click(function () {
  new_session();
});

$("#welcome-avanti").click(function() {
  new_session();
});

function new_session (){
  $("#welcome").hide();
  $(".categoria").show();
  load_from_famiglia();
}

//===============================================================
//====================== FROM FAMIGLIA ==========================
//===============================================================

$("#menu-famiglia-button").click(function() {
  load_from_famiglia();
});

function load_from_famiglia() {
  load_partial("partials/famiglia.html", "#form-container", from_famiglia());
}

function from_famiglia(){
  //Collego i bottono +,-
  increment_inpunt_value();
  decrement_input_value();

  $("#famiglia-avanti").click(function() {
    var data = {};
    $.each($('#famiglia-caller').serializeArray(), function (i, el){
      data[el.name] = el.value;
    });
    user_new_data.famiglia = data;
  });
}

<|endoftext|>


<commit_before>(function ($) {
   'use strict';

    $.widget( "ui.global_nav", {
        _init: function() {
            this.init();
        },

        init: function() {
            var me = this;

            me.document            = $(document),
            me.body                = $('body:eq(0)'),
            me.menuButton          = $(me.element.find('#toggle-menu')[0]);

            me.document.on('click', me._handleDocumentClick.bind(me));
            me.document.on('menu:close', me._closeMenu.bind(me));

            if ('ontouchstart' in document.documentElement) {
                if ($('.global-nav__menu__dropdown').length > 0) {
                    var openLink = false;
                    $('body').prepend('

');
                    $('.global-nav__menu__dropdown_close').on('touchstart', function(e) {
                        $('.global-nav__menu__dropdown').removeClass('touch-open');
                        $(this).hide();
                        openLink = false;
                    });
                    $('.global-nav__menu__dropdown').each(function(i) {
                        $(this).find('a:first').on('touchstart', function(e) {
                            if (openLink == false) {
                                e.preventDefault();
                                $(this).parent().addClass('touch-open');
                                $('.global-nav__menu__dropdown_close').show();
                                openLink = true;
                            } else {
                                if ($(this).parent().hasClass('touch-open') == false) {
                                    $('.global-nav__menu__dropdown').removeClass('touch-open');
                                    e.preventDefault();
                                    $(this).parent().addClass('touch-open');
                                }
                            }
                        });
                    });
                }
            }
        },

        _handleDocumentClick: function(event) {

            let $target = $(event.originalEvent.target),
                isOpen = $('.global-nav:eq(0)').hasClass('is-open'),
                me = this;

            // Clicked on/in toggle menu button
            if ($target.closest('[class*="toggle-menu"]').size() > 0) {
                me._toggleMenu(event);
                event.preventDefault();
                return;
            }

            // Clicked on/in menu close button
            if ($target.closest('[class*="nav__close"]').size() > 0) {
                me._closeMenu(event);
                event.preventDefault();
                return;
            }

            //Clicked outside of menu
            if ($target.closest('[class*="global-nav__inner"]').size() == 0) {
                if (isOpen) {
                    me._closeMenu(event);
                    event.preventDefault();
                    return;
                }
            }
        },

        _closeMenu: function(event) {
            var me = this;
            me._toggleMenu(event, true);
        },

        _toggleMenu: function(event, close) {

            var me = this;

            me.menuButton.toggleClass('is-active');

            if (close) {
                me.body.removeClass('is-menu-visible');
                me.element.removeClass('is-open');
                me.menuButton.removeClass('is-active');
            } else {
                if(me.menuButton.hasClass('is-active')) {
                    me.element.addClass('is-open');
                    me.body.addClass('is-menu-visible');
                } else {
                    me.element.removeClass('is-open');
                    me.body.removeClass('is-menu-visible');
                }
            }

            event.preventDefault();

        }
    });

})(jQuery);
<commit_msg>[base] global nav, tweaking<commit_after>(function ($) {
   'use strict';

    $.widget( "ui.global_nav", {
        _init: function() {
            this.init();
        },

        init: function() {
            var me = this;

            me.document            = $(document),
            me.body                = $('body:eq(0)'),
            me.menuButton          = $(me.element.find('#toggle-menu')[0]);

            me.document.on('click', me._handleDocumentClick.bind(me));
            me.document.on('menu:close', me._closeMenu.bind(me));

            if ('ontouchstart' in document.documentElement) {
                if ($('.global-nav__menu__dropdown').length > 0) {
                    var openLink = false;
                    $('body').prepend('

');
                    $('.global-nav__menu__dropdown_close').on('touchstart', function(e) {
                        $('.global-nav__menu__dropdown').removeClass('touch-open');
                        $(this).hide();
                        openLink = false;
                    });
                    $('.global-nav__menu__dropdown').each(function(i) {
                        $(this).find('a:first').on('touchstart', function(e) {
                            if (openLink == false) {
                                e.preventDefault();
                                $(this).parent().addClass('touch-open');
                                $('.global-nav__menu__dropdown_close').show();
                                openLink = true;
                            } else {
                                if ($(this).parent().hasClass('touch-open') == false) {
                                    $('.global-nav__menu__dropdown').removeClass('touch-open');
                                    e.preventDefault();
                                    $(this).parent().addClass('touch-open');
                                }
                            }
                        });
                    });
                }
            }
        },

        _handleDocumentClick: function(event) {

            let $target = $(event.originalEvent.target),
                isOpen = $('.global-nav:eq(0)').hasClass('is-open'),
                me = this;

            // Clicked on/in toggle menu button
            if ($target.closest('[class*="toggle-menu"]').size() > 0) {
                me._toggleMenu(event);
                event.preventDefault();
                return;
            }

            // Clicked on/in menu close button
            if ($target.closest('[class*="nav__close"]').size() > 0) {
                me._closeMenu(event);
                event.preventDefault();
                return;
            }

            //Clicked outside of menu
            if ($target.closest('[class*="global-nav"]').size() == 0) {
                if (isOpen) {
                    me._closeMenu(event);
                    event.preventDefault();
                    return;
                }
            }
        },

        _closeMenu: function(event) {
            var me = this;
            me._toggleMenu(event, true);
        },

        _toggleMenu: function(event, close) {

            var me = this;

            me.menuButton.toggleClass('is-active');

            if (close) {
                me.body.removeClass('is-menu-visible');
                me.element.removeClass('is-open');
                me.menuButton.removeClass('is-active');
            } else {
                if(me.menuButton.hasClass('is-active')) {
                    me.element.addClass('is-open');
                    me.body.addClass('is-menu-visible');
                } else {
                    me.element.removeClass('is-open');
                    me.body.removeClass('is-menu-visible');
                }
            }

            event.preventDefault();

        }
    });

})(jQuery);
<|endoftext|>