<commit_before>const SINGLE_QUOTE      = '\''.charCodeAt(0);
const DOUBLE_QUOTE      =  '"'.charCodeAt(0);
const BACKSLASH         = '\\'.charCodeAt(0);
const SLASH             =  '/'.charCodeAt(0);
const NEWLINE           = '\n'.charCodeAt(0);
const SPACE             =  ' '.charCodeAt(0);
const FEED              = '\f'.charCodeAt(0);
const TAB               = '\t'.charCodeAt(0);
const CR                = '\r'.charCodeAt(0);
const OPEN_PARENTHESES  =  '('.charCodeAt(0);
const CLOSE_PARENTHESES =  ')'.charCodeAt(0);
const OPEN_CURLY        =  '{'.charCodeAt(0);
const CLOSE_CURLY       =  '}'.charCodeAt(0);
const SEMICOLON         =  ';'.charCodeAt(0);
const ASTERICK          =  '*'.charCodeAt(0);
const COLON             =  ':'.charCodeAt(0);
const AT                =  '@'.charCodeAt(0);

const RE_AT_END      = /[ \n\t\r\{\(\)'"\\;/]/g;
const RE_WORD_END    = /[ \n\t\r\(\)\{\}:;@!'"\\]|\/(?=\*)/g;
const RE_BAD_BRACKET = /.[\\\/\("'\n]/;

export default function safeTokenize(input) {
    let tokens = [];
    let css    = input.css.valueOf();

    let code, next, quote, lines, last, content, escape,
        nextLine, nextOffset, escaped, escapePos, prev, n;

    let length = css.length;
    let offset = -1;
    let line   =  1;
    let pos    =  0;

    function fixUnclosed(what, end) {
        css += end;
        next = css.length - 1;
    }

    while ( pos < length ) {
        code = css.charCodeAt(pos);

        if ( code === NEWLINE ) {
            offset = pos;
            line  += 1;
        }

        switch ( code ) {
        case NEWLINE:
        case SPACE:
        case TAB:
        case CR:
        case FEED:
            next = pos;
            do {
                next += 1;
                code = css.charCodeAt(next);
                if ( code === NEWLINE ) {
                    offset = next;
                    line  += 1;
                }
            } while ( code === SPACE   ||
                      code === NEWLINE ||
                      code === TAB     ||
                      code === CR      ||
                      code === FEED );

            tokens.push(['space', css.slice(pos, next)]);
            pos = next - 1;
            break;

        case OPEN_CURLY:
            tokens.push(['{', '{', line, pos - offset]);
            break;

        case CLOSE_CURLY:
            tokens.push(['}', '}', line, pos - offset]);
            break;

        case COLON:
            tokens.push([':', ':', line, pos - offset]);
            break;

        case SEMICOLON:
            tokens.push([';', ';', line, pos - offset]);
            break;

        case OPEN_PARENTHESES:
            prev = tokens.length ? tokens[tokens.length - 1][1] : '';
            n    = css.charCodeAt(pos + 1);
            if ( prev === 'url' && n !== SINGLE_QUOTE && n !== DOUBLE_QUOTE &&
                                   n !== SPACE && n !== NEWLINE && n !== TAB &&
                                   n !== FEED && n !== CR ) {
                next = pos;
                do {
                    escaped = false;
                    next    = css.indexOf(')', next + 1);
                    if ( next === -1 ) fixUnclosed('bracket', ')');
                    escapePos = next;
                    while ( css.charCodeAt(escapePos - 1) === BACKSLASH ) {
                        escapePos -= 1;
                        escaped = !escaped;
                    }
                } while ( escaped );

                tokens.push(['brackets', css.slice(pos, next + 1),
                    line, pos  - offset,
                    line, next - offset
                ]);
                pos = next;

            } else {
                next    = css.indexOf(')', pos + 1);
                content = css.slice(pos, next + 1);

                if ( next === -1 || RE_BAD_BRACKET.test(content) ) {
                    tokens.push(['(', '(', line, pos - offset]);
                } else {
                    tokens.push(['brackets', content,
                        line, pos  - offset,
                        line, next - offset
                    ]);
                    pos = next;
                }
            }

            break;

        case CLOSE_PARENTHESES:
            tokens.push([')', ')', line, pos - offset]);
            break;

        case SINGLE_QUOTE:
        case DOUBLE_QUOTE:
            quote = code === SINGLE_QUOTE ? '\'' : '"';
            next  = pos;
            do {
                escaped = false;
                next    = css.indexOf(quote, next + 1);
                if ( next === -1 ) fixUnclosed('quote', quote);
                escapePos = next;
                while ( css.charCodeAt(escapePos - 1) === BACKSLASH ) {
                    escapePos -= 1;
                    escaped = !escaped;
                }
            } while ( escaped );

            content = css.slice(pos, next + 1);
            lines   = content.split('\n');
            last    = lines.length - 1;

            if ( last > 0 ) {
                nextLine   = line + last;
                nextOffset = next - lines[last].length;
            } else {
                nextLine   = line;
                nextOffset = offset;
            }

            tokens.push(['string', css.slice(pos, next + 1),
                line, pos  - offset,
                nextLine, next - nextOffset
            ]);

            offset = nextOffset;
            line   = nextLine;
            pos    = next;
            break;

        case AT:
            RE_AT_END.lastIndex = pos + 1;
            RE_AT_END.test(css);
            if ( RE_AT_END.lastIndex === 0 ) {
                next = css.length - 1;
            } else {
                next = RE_AT_END.lastIndex - 2;
            }
            tokens.push(['at-word', css.slice(pos, next + 1),
                line, pos  - offset,
                line, next - offset
            ]);
            pos = next;
            break;

        case BACKSLASH:
            next   = pos;
            escape = true;
            while ( css.charCodeAt(next + 1) === BACKSLASH ) {
                next  += 1;
                escape = !escape;
            }
            code = css.charCodeAt(next + 1);
            if ( escape && (code !== SLASH   &&
                            code !== SPACE   &&
                            code !== NEWLINE &&
                            code !== TAB     &&
                            code !== CR      &&
                            code !== FEED ) ) {
                next += 1;
            }
            tokens.push(['word', css.slice(pos, next + 1),
                line, pos  - offset,
                line, next - offset
            ]);
            pos = next;
            break;

        default:
            if ( code === SLASH && css.charCodeAt(pos + 1) === ASTERICK ) {
                next = css.indexOf('*/', pos + 2) + 1;
                if ( next === 0 ) fixUnclosed('comment', '*/');

                content = css.slice(pos, next + 1);
                lines   = content.split('\n');
                last    = lines.length - 1;

                if ( last > 0 ) {
                    nextLine   = line + last;
                    nextOffset = next - lines[last].length;
                } else {
                    nextLine   = line;
                    nextOffset = offset;
                }

                tokens.push(['comment', content,
                    line,     pos  - offset,
                    nextLine, next - nextOffset
                ]);

                offset = nextOffset;
                line   = nextLine;
                pos    = next;

            } else {
                RE_WORD_END.lastIndex = pos + 1;
                RE_WORD_END.test(css);
                if ( RE_WORD_END.lastIndex === 0 ) {
                    next = css.length - 1;
                } else {
                    next = RE_WORD_END.lastIndex - 2;
                }

                tokens.push(['word', css.slice(pos, next + 1),
                    line, pos  - offset,
                    line, next - offset
                ]);
                pos = next;
            }

            break;
        }

        pos++;
    }

    return tokens;
}
<commit_msg>Backport line feed support<commit_after>const SINGLE_QUOTE      = '\''.charCodeAt(0);
const DOUBLE_QUOTE      =  '"'.charCodeAt(0);
const BACKSLASH         = '\\'.charCodeAt(0);
const SLASH             =  '/'.charCodeAt(0);
const NEWLINE           = '\n'.charCodeAt(0);
const SPACE             =  ' '.charCodeAt(0);
const FEED              = '\f'.charCodeAt(0);
const TAB               = '\t'.charCodeAt(0);
const CR                = '\r'.charCodeAt(0);
const OPEN_PARENTHESES  =  '('.charCodeAt(0);
const CLOSE_PARENTHESES =  ')'.charCodeAt(0);
const OPEN_CURLY        =  '{'.charCodeAt(0);
const CLOSE_CURLY       =  '}'.charCodeAt(0);
const SEMICOLON         =  ';'.charCodeAt(0);
const ASTERICK          =  '*'.charCodeAt(0);
const COLON             =  ':'.charCodeAt(0);
const AT                =  '@'.charCodeAt(0);

const RE_AT_END      = /[ \n\t\r\f\{\(\)'"\\;/]/g;
const RE_WORD_END    = /[ \n\t\r\f\(\)\{\}:;@!'"\\]|\/(?=\*)/g;
const RE_BAD_BRACKET = /.[\\\/\("'\n]/;

export default function safeTokenize(input) {
    let tokens = [];
    let css    = input.css.valueOf();

    let code, next, quote, lines, last, content, escape,
        nextLine, nextOffset, escaped, escapePos, prev, n;

    let length = css.length;
    let offset = -1;
    let line   =  1;
    let pos    =  0;

    function fixUnclosed(what, end) {
        css += end;
        next = css.length - 1;
    }

    while ( pos < length ) {
        code = css.charCodeAt(pos);

        if ( code === NEWLINE || code === FEED ||
             code === CR && css.charCodeAt(pos + 1) !== NEWLINE ) {
            offset = pos;
            line  += 1;
        }

        switch ( code ) {
        case NEWLINE:
        case SPACE:
        case TAB:
        case CR:
        case FEED:
            next = pos;
            do {
                next += 1;
                code = css.charCodeAt(next);
                if ( code === NEWLINE ) {
                    offset = next;
                    line  += 1;
                }
            } while ( code === SPACE   ||
                      code === NEWLINE ||
                      code === TAB     ||
                      code === CR      ||
                      code === FEED );

            tokens.push(['space', css.slice(pos, next)]);
            pos = next - 1;
            break;

        case OPEN_CURLY:
            tokens.push(['{', '{', line, pos - offset]);
            break;

        case CLOSE_CURLY:
            tokens.push(['}', '}', line, pos - offset]);
            break;

        case COLON:
            tokens.push([':', ':', line, pos - offset]);
            break;

        case SEMICOLON:
            tokens.push([';', ';', line, pos - offset]);
            break;

        case OPEN_PARENTHESES:
            prev = tokens.length ? tokens[tokens.length - 1][1] : '';
            n    = css.charCodeAt(pos + 1);
            if ( prev === 'url' && n !== SINGLE_QUOTE && n !== DOUBLE_QUOTE &&
                                   n !== SPACE && n !== NEWLINE && n !== TAB &&
                                   n !== FEED && n !== CR ) {
                next = pos;
                do {
                    escaped = false;
                    next    = css.indexOf(')', next + 1);
                    if ( next === -1 ) fixUnclosed('bracket', ')');
                    escapePos = next;
                    while ( css.charCodeAt(escapePos - 1) === BACKSLASH ) {
                        escapePos -= 1;
                        escaped = !escaped;
                    }
                } while ( escaped );

                tokens.push(['brackets', css.slice(pos, next + 1),
                    line, pos  - offset,
                    line, next - offset
                ]);
                pos = next;

            } else {
                next    = css.indexOf(')', pos + 1);
                content = css.slice(pos, next + 1);

                if ( next === -1 || RE_BAD_BRACKET.test(content) ) {
                    tokens.push(['(', '(', line, pos - offset]);
                } else {
                    tokens.push(['brackets', content,
                        line, pos  - offset,
                        line, next - offset
                    ]);
                    pos = next;
                }
            }

            break;

        case CLOSE_PARENTHESES:
            tokens.push([')', ')', line, pos - offset]);
            break;

        case SINGLE_QUOTE:
        case DOUBLE_QUOTE:
            quote = code === SINGLE_QUOTE ? '\'' : '"';
            next  = pos;
            do {
                escaped = false;
                next    = css.indexOf(quote, next + 1);
                if ( next === -1 ) fixUnclosed('quote', quote);
                escapePos = next;
                while ( css.charCodeAt(escapePos - 1) === BACKSLASH ) {
                    escapePos -= 1;
                    escaped = !escaped;
                }
            } while ( escaped );

            content = css.slice(pos, next + 1);
            lines   = content.split('\n');
            last    = lines.length - 1;

            if ( last > 0 ) {
                nextLine   = line + last;
                nextOffset = next - lines[last].length;
            } else {
                nextLine   = line;
                nextOffset = offset;
            }

            tokens.push(['string', css.slice(pos, next + 1),
                line, pos  - offset,
                nextLine, next - nextOffset
            ]);

            offset = nextOffset;
            line   = nextLine;
            pos    = next;
            break;

        case AT:
            RE_AT_END.lastIndex = pos + 1;
            RE_AT_END.test(css);
            if ( RE_AT_END.lastIndex === 0 ) {
                next = css.length - 1;
            } else {
                next = RE_AT_END.lastIndex - 2;
            }
            tokens.push(['at-word', css.slice(pos, next + 1),
                line, pos  - offset,
                line, next - offset
            ]);
            pos = next;
            break;

        case BACKSLASH:
            next   = pos;
            escape = true;
            while ( css.charCodeAt(next + 1) === BACKSLASH ) {
                next  += 1;
                escape = !escape;
            }
            code = css.charCodeAt(next + 1);
            if ( escape && (code !== SLASH   &&
                            code !== SPACE   &&
                            code !== NEWLINE &&
                            code !== TAB     &&
                            code !== CR      &&
                            code !== FEED ) ) {
                next += 1;
            }
            tokens.push(['word', css.slice(pos, next + 1),
                line, pos  - offset,
                line, next - offset
            ]);
            pos = next;
            break;

        default:
            if ( code === SLASH && css.charCodeAt(pos + 1) === ASTERICK ) {
                next = css.indexOf('*/', pos + 2) + 1;
                if ( next === 0 ) fixUnclosed('comment', '*/');

                content = css.slice(pos, next + 1);
                lines   = content.split('\n');
                last    = lines.length - 1;

                if ( last > 0 ) {
                    nextLine   = line + last;
                    nextOffset = next - lines[last].length;
                } else {
                    nextLine   = line;
                    nextOffset = offset;
                }

                tokens.push(['comment', content,
                    line,     pos  - offset,
                    nextLine, next - nextOffset
                ]);

                offset = nextOffset;
                line   = nextLine;
                pos    = next;

            } else {
                RE_WORD_END.lastIndex = pos + 1;
                RE_WORD_END.test(css);
                if ( RE_WORD_END.lastIndex === 0 ) {
                    next = css.length - 1;
                } else {
                    next = RE_WORD_END.lastIndex - 2;
                }

                tokens.push(['word', css.slice(pos, next + 1),
                    line, pos  - offset,
                    line, next - offset
                ]);
                pos = next;
            }

            break;
        }

        pos++;
    }

    return tokens;
}
<|endoftext|>


<commit_before>'use strict';

const _ = require('lodash'),
  bluebird = require('bluebird'),
  components = require('../services/components'),
  composer = require('../composer'),
  db = require('../services/db'),
  notifications = require('./notifications'),
  references = require('../services/references'),
  siteService = require('./sites'),
  uid = require('../uid');

/**
 * @param {string} uri
 * @param {{}} data
 * @param {[]} ops
 */
function addOp(uri, data, ops) {
  ops.push({
    type: 'put',
    key: uri,
    value: JSON.stringify(data)
  });

  return ops;
}

/**
 * True of reference object has a string in _ref that includes "/instances/"
 * @param {object} data
 * @returns {boolean}
 */
function isInstanceReferenceObject(data) {
  return _.isString(data._ref) && data._ref.indexOf('/instances/') > -1;
}

/**
 * Get a reference that is unique, but of the same component type as original.
 * @param {string} uri
 * @returns {string}
 */
function renameReferenceUniquely(uri) {
  const prefix = uri.substr(0, uri.indexOf('/components/'));

  return prefix + '/components/' + components.getName(uri) + '/instances/' + uid.get();
}

/**
 * Clone all instance components that are referenced by this page data, and maintain the data's object structure.
 *
 * @param {object} pageData
 * @param {object} [locals]
 * @returns {Promise}
 */
function getPageClonePutOperations(pageData, locals) {
  return bluebird.all(_.reduce(pageData, function (promises, pageValue, pageKey) {
    if (typeof pageValue === 'string' && components.getName(pageValue)) {
      //for all strings that are component references
      promises.push(components.get(pageValue, locals).then(function (refData) {
        //only follow the paths of instance references.  Don't clone default components
        return composer.resolveComponentReferences(refData, locals, isInstanceReferenceObject);
      }).then(function (resolvedData) {
        //for each instance reference within resolved data
        _.each(_.listDeepObjects(resolvedData, isInstanceReferenceObject), function (obj) {
          obj._ref = renameReferenceUniquely(obj._ref);
        });

        //rename reference in pageData
        const ref = renameReferenceUniquely(pageValue);
        pageData[pageKey] = ref;

        //put new data using cascading PUT at place that page now points
        return components.getPutOperations(ref, resolvedData, locals);
      }));
    } else {
      //for all object-like things (i.e., objects and arrays)
      promises = promises.concat(getPageClonePutOperations(pageValue, locals));
    }
    return promises;
  }, [])).then(_.flatten); //only one level of flattening needed
}

/**
 * Applies operations, then returns last (root) op's value.
 *
 * @param {object} site
 */
function applyBatch(site) {
  return function (ops) {
    const lastOp = _.last(ops),
      lastValue = lastOp && JSON.parse(lastOp.value);

    return db.batch(ops).then(function () {
      // if published, notify listeners
      if (_.endsWith(lastOp.key, '@published')) {
        notifications.notify(site, 'published', lastValue);
      }
    }).return(lastValue);
  };
}

/**
 * Replace the referenced things in the page data with a different version
 * @param {object} data
 * @param {string} version
 * @returns object
 */
function replacePageReferenceVersions(data, version) {
  const replaceVersion = _.partial(references.replaceVersion, _, version);

  return _.mapValues(data, function (value) {
    if (references.isUri(value)) {
      return replaceVersion(value);
    } else if (_.isArray(value)) {
      return _.map(value, replaceVersion);
    } else {
      return value;
    }
  });
}

/**
 * Get latest data of uri@latest
 * @param {string} uri
 * @returns {Promise}
 */
function getLatestData(uri) {
  return db.get(references.replaceVersion(uri)).then(JSON.parse);
}

/**
 * @param {object} locals
 * @returns {Function}
 */
function compose(locals) {
  return function (data) {
    return composer.resolveComponentReferences(data, locals);
  };
}

/**
 * Get a list of all operations with all references converted to @published
 * @returns {function}
 */
function getRecursivePublishedPutOperations(locals) {
  return function (rootComponentRef) {
    const published = 'published';

    /**
     * 1) Get reference (could be latest, could be other)
     * 2) Get all references within reference
     * 3) Replace all references with @published (including root reference)
     * 4) Get list of put operations needed
     */
    return components.get(rootComponentRef, locals)
      .then(compose(locals))
      .then(references.replaceAllVersions(published))
      .then(function (data) {
        return components.getPutOperations(references.replaceVersion(rootComponentRef, published), data, locals);
      });
  };
}

function getSite(prefix, locals) {
  const site = locals && locals.site;

  return site || siteService.getSiteFromPrefix(prefix);
}

/**
 * Cannot contain any empty value (null, '', undefined, false)
 * @param {object} data
 * @throws
 */
function assertNoEmptyValues(data) {
  _.each(data, function (value) {
    if (!value) {
      throw new Error('Client: page cannot have empty values');
    }
  });

  _.each(_.listDeepObjects(data), assertNoEmptyValues);
}

/**
 * Publish a uri
 * @param {string} uri
 * @param {object} [data]
 * @param {object} [locals]
 * @returns {Promise}
 */
function publish(uri, data, locals) {
  const prefix = references.getPagePrefix(uri),
    site = getSite(prefix, locals);

  return bluebird.try(function () {
    if (data && _.size(data) > 0) {
      // if they actually gave us something, use it
      assertNoEmptyValues(data);
      return data;
    } else {
      // otherwise, assume they meant whatever is in @latest
      return getLatestData(uri);
    }
  }).then(function (pageData) {
    const published = 'published',
      canonicalUrl = pageData.url,
      componentList = references.getPageReferences(pageData);

    if (!references.isUrl(canonicalUrl)) {
      throw new Error('Client: Page must have valid url to publish.');
    }

    return bluebird.map(componentList, getRecursivePublishedPutOperations(locals))
      .then(_.flatten) // only one level of flattening needed, because getPutOperations should have flattened its list already
      .then(function (ops) {
        // convert the data to all @published
        pageData = replacePageReferenceVersions(pageData, published);

        // make public
        ops.push({
          type: 'put',
          key: prefix + '/uris/' + new Buffer(references.urlToUri(canonicalUrl)).toString('base64'),
          value: references.replaceVersion(uri)
        });

        // add page PUT operation last
        return addOp(references.replaceVersion(uri, published), pageData, ops);
      });
  }).then(applyBatch(site));
}

/**
 * First draft
 * @param {string} uri
 * @param {object} data
 * @param {object} [locals]
 * @returns {Promise}
 */
function create(uri, data, locals) {
  const layoutReference = data && data.layout,
    pageData = data && references.omitPageConfiguration(data),
    prefix = uri.substr(0, uri.indexOf('/pages')),
    site = getSite(prefix, locals),
    pageReference = prefix + '/pages/' + uid.get();

  if (!layoutReference) {
    throw new Error('Client: Data missing layout reference.');
  }

  return components.get(layoutReference, locals).then(function () {

    return getPageClonePutOperations(pageData).then(function (ops) {
      pageData.layout = layoutReference;

      return addOp(pageReference, pageData, ops);
    });
  }).then(applyBatch(site)).then(function (newPage) {
    // if successful, return new page object, but include the (optional) self reference to the new page.
    newPage._ref = pageReference;
    return newPage;
  });
}

module.exports.create = create;
module.exports.publish = publish;
module.exports.replacePageReferenceVersions = replacePageReferenceVersions;
<commit_msg>add locals to page service<commit_after>'use strict';

const _ = require('lodash'),
  bluebird = require('bluebird'),
  components = require('../services/components'),
  composer = require('../composer'),
  db = require('../services/db'),
  notifications = require('./notifications'),
  references = require('../services/references'),
  siteService = require('./sites'),
  uid = require('../uid');

/**
 * @param {string} uri
 * @param {{}} data
 * @param {[]} ops
 */
function addOp(uri, data, ops) {
  ops.push({
    type: 'put',
    key: uri,
    value: JSON.stringify(data)
  });

  return ops;
}

/**
 * True of reference object has a string in _ref that includes "/instances/"
 * @param {object} data
 * @returns {boolean}
 */
function isInstanceReferenceObject(data) {
  return _.isString(data._ref) && data._ref.indexOf('/instances/') > -1;
}

/**
 * Get a reference that is unique, but of the same component type as original.
 * @param {string} uri
 * @returns {string}
 */
function renameReferenceUniquely(uri) {
  const prefix = uri.substr(0, uri.indexOf('/components/'));

  return prefix + '/components/' + components.getName(uri) + '/instances/' + uid.get();
}

/**
 * Clone all instance components that are referenced by this page data, and maintain the data's object structure.
 *
 * @param {object} pageData
 * @param {object} locals
 * @returns {Promise}
 */
function getPageClonePutOperations(pageData, locals) {
  return bluebird.all(_.reduce(pageData, function (promises, pageValue, pageKey) {
    if (typeof pageValue === 'string' && components.getName(pageValue)) {
      //for all strings that are component references
      promises.push(components.get(pageValue, locals).then(function (refData) {
        //only follow the paths of instance references.  Don't clone default components
        return composer.resolveComponentReferences(refData, locals, isInstanceReferenceObject);
      }).then(function (resolvedData) {
        //for each instance reference within resolved data
        _.each(_.listDeepObjects(resolvedData, isInstanceReferenceObject), function (obj) {
          obj._ref = renameReferenceUniquely(obj._ref);
        });

        //rename reference in pageData
        const ref = renameReferenceUniquely(pageValue);
        pageData[pageKey] = ref;

        //put new data using cascading PUT at place that page now points
        return components.getPutOperations(ref, resolvedData, locals);
      }));
    } else {
      //for all object-like things (i.e., objects and arrays)
      promises = promises.concat(getPageClonePutOperations(pageValue, locals));
    }
    return promises;
  }, [])).then(_.flatten); //only one level of flattening needed
}

/**
 * Applies operations, then returns last (root) op's value.
 *
 * @param {object} site
 */
function applyBatch(site) {
  return function (ops) {
    const lastOp = _.last(ops),
      lastValue = lastOp && JSON.parse(lastOp.value);

    return db.batch(ops).then(function () {
      // if published, notify listeners
      if (_.endsWith(lastOp.key, '@published')) {
        notifications.notify(site, 'published', lastValue);
      }
    }).return(lastValue);
  };
}

/**
 * Replace the referenced things in the page data with a different version
 * @param {object} data
 * @param {string} version
 * @returns object
 */
function replacePageReferenceVersions(data, version) {
  const replaceVersion = _.partial(references.replaceVersion, _, version);

  return _.mapValues(data, function (value) {
    if (references.isUri(value)) {
      return replaceVersion(value);
    } else if (_.isArray(value)) {
      return _.map(value, replaceVersion);
    } else {
      return value;
    }
  });
}

/**
 * Get latest data of uri@latest
 * @param {string} uri
 * @returns {Promise}
 */
function getLatestData(uri) {
  return db.get(references.replaceVersion(uri)).then(JSON.parse);
}

/**
 * @param {object} locals
 * @returns {Function}
 */
function compose(locals) {
  return function (data) {
    return composer.resolveComponentReferences(data, locals);
  };
}

/**
 * Get a list of all operations with all references converted to @published
 * @returns {function}
 */
function getRecursivePublishedPutOperations(locals) {
  return function (rootComponentRef) {
    const published = 'published';

    /**
     * 1) Get reference (could be latest, could be other)
     * 2) Get all references within reference
     * 3) Replace all references with @published (including root reference)
     * 4) Get list of put operations needed
     */
    return components.get(rootComponentRef, locals)
      .then(compose(locals))
      .then(references.replaceAllVersions(published))
      .then(function (data) {
        return components.getPutOperations(references.replaceVersion(rootComponentRef, published), data, locals);
      });
  };
}

function getSite(prefix, locals) {
  const site = locals && locals.site;

  return site || siteService.getSiteFromPrefix(prefix);
}

/**
 * Cannot contain any empty value (null, '', undefined, false)
 * @param {object} data
 * @throws
 */
function assertNoEmptyValues(data) {
  _.each(data, function (value) {
    if (!value) {
      throw new Error('Client: page cannot have empty values');
    }
  });

  _.each(_.listDeepObjects(data), assertNoEmptyValues);
}

/**
 * Publish a uri
 * @param {string} uri
 * @param {object} [data]
 * @param {object} [locals]
 * @returns {Promise}
 */
function publish(uri, data, locals) {
  const prefix = references.getPagePrefix(uri),
    site = getSite(prefix, locals);

  return bluebird.try(function () {
    if (data && _.size(data) > 0) {
      // if they actually gave us something, use it
      assertNoEmptyValues(data);
      return data;
    } else {
      // otherwise, assume they meant whatever is in @latest
      return getLatestData(uri);
    }
  }).then(function (pageData) {
    const published = 'published',
      canonicalUrl = pageData.url,
      componentList = references.getPageReferences(pageData);

    if (!references.isUrl(canonicalUrl)) {
      throw new Error('Client: Page must have valid url to publish.');
    }

    return bluebird.map(componentList, getRecursivePublishedPutOperations(locals))
      .then(_.flatten) // only one level of flattening needed, because getPutOperations should have flattened its list already
      .then(function (ops) {
        // convert the data to all @published
        pageData = replacePageReferenceVersions(pageData, published);

        // make public
        ops.push({
          type: 'put',
          key: prefix + '/uris/' + new Buffer(references.urlToUri(canonicalUrl)).toString('base64'),
          value: references.replaceVersion(uri)
        });

        // add page PUT operation last
        return addOp(references.replaceVersion(uri, published), pageData, ops);
      });
  }).then(applyBatch(site));
}

/**
 * First draft
 * @param {string} uri
 * @param {object} data
 * @param {object} [locals]
 * @returns {Promise}
 */
function create(uri, data, locals) {
  const layoutReference = data && data.layout,
    pageData = data && references.omitPageConfiguration(data),
    prefix = uri.substr(0, uri.indexOf('/pages')),
    site = getSite(prefix, locals),
    pageReference = prefix + '/pages/' + uid.get();

  if (!layoutReference) {
    throw new Error('Client: Data missing layout reference.');
  }

  return components.get(layoutReference, locals).then(function () {

    return getPageClonePutOperations(pageData, locals).then(function (ops) {
      pageData.layout = layoutReference;

      return addOp(pageReference, pageData, ops);
    });
  }).then(applyBatch(site)).then(function (newPage) {
    // if successful, return new page object, but include the (optional) self reference to the new page.
    newPage._ref = pageReference;
    return newPage;
  });
}

module.exports.create = create;
module.exports.publish = publish;
module.exports.replacePageReferenceVersions = replacePageReferenceVersions;
<|endoftext|>


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

module.exports = (function () {

	var o = function (graph) {
		HexagonNode.apply(this, arguments);

		this.attributes(["hexagon"])
			.type("Hexagon");
	};
	o.prototype = Object.create(HexagonNode.prototype);
	o.prototype.constructor = o;

	return o;
}());
<commit_msg>Change hexagon type to rule<commit_after>var HexagonNode = require("../HexagonNode");

module.exports = (function () {

	var o = function (graph) {
		HexagonNode.apply(this, arguments);

		this.type("Rule");
	};
	o.prototype = Object.create(HexagonNode.prototype);
	o.prototype.constructor = o;

	return o;
}());
<|endoftext|>


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

/*global Wirecloud*/
if (!Wirecloud.help) {
    // TODO this line should live in another file
    Wirecloud.help = {};
}

(function () {

    "use strict";

    /*************************************************************************
     * Constructor
     *************************************************************************/
    var Tutorial = function Tutorial(tut_id) {
        var i, key;

        if (!isVal(tut_id)){
            return null;
        }
        this.stepActive = null;
        this.steps = [];

        this.controlLayer = document.createElement("div");
        this.controlLayerUp = document.createElement("div");
        this.controlLayerDown = document.createElement("div");
        this.controlLayerLeft = document.createElement("div");
        this.controlLayerRight = document.createElement("div");
        this.controlLayer.addClassName("controlLayer");
        this.controlLayerUp.addClassName("controlLayerUp");
        this.controlLayerDown.addClassName("controlLayerDown");
        this.controlLayerLeft.addClassName("controlLayerLeft");
        this.controlLayerRight.addClassName("controlLayerRight");
        this.controlLayer.appendChild(this.controlLayerUp);
        this.controlLayer.appendChild(this.controlLayerDown);
        this.controlLayer.appendChild(this.controlLayerLeft);
        this.controlLayer.appendChild(this.controlLayerRight);

        document.body.appendChild(this.controlLayer);
        this.resetControlLayer();

        this.msgLayer = document.createElement("div");
        this.msgLayer.addClassName("msgLayer");
        document.body.appendChild(this.msgLayer);

        this.instructions = getTutorial(tut_id);

        var mapping = {
            'simpleDescription': Wirecloud.ui.Tutorial.SimpleDescription,
            'userAction': Wirecloud.ui.Tutorial.UserAction,
            'formAction': Wirecloud.ui.Tutorial.FormAction,
            'autoAction': Wirecloud.ui.Tutorial.AutoAction,
        };

        // creating simpleDescriptions
        for (i = 0; i < this.instructions.length; i ++) {
            var constructor = mapping[this.instructions[i].type];
            this.steps[i] = new constructor(this, this.instructions[i]);

            if (i == 0) {
                this.steps[i].wrapperElement.addClassName("activeStep");
                this.stepActive = this.steps[i];
            }
            if (i == this.instructions.length-1) {
                this.steps[i].setLast();
            } else {
                this.steps[i].setNext();
            }
        }
    };

    /**
     * Next Step
     */
    Tutorial.prototype.nextStep = function nextStep() {
        var order;

        order = this.steps.indexOf(this.stepActive );
        if (order < this.steps.length) {
            this.stepActive.destroy();
            this.resetControlLayer(false);
            this.stepActive = this.steps[this.steps.indexOf(this.stepActive) + 1];
            this.stepActive.activate();
        } else {
            this.destroy;
        }
    };

    /**
     * reset controlLayers positions
     */
    Tutorial.prototype.resetControlLayer = function resetControlLayer(isTransparent) {
        this.controlLayerUp.style.opacity = 0.4;
        //up
        this.controlLayerUp.style.height = '100%';
        this.controlLayerUp.style.width = '100%';
        this.controlLayerUp.style.top = 0;
        this.controlLayerUp.style.left = 0;
        //down
        this.controlLayerDown.style.height = 0;
        this.controlLayerDown.style.width = 0;
        this.controlLayerDown.style.top = 0;
        this.controlLayerDown.style.left = 0;
        //right
        this.controlLayerRight.style.height = 0;
        this.controlLayerRight.style.width = 0;
        this.controlLayerRight.style.top = 0;
        this.controlLayerRight.style.left = 0;
        //left
        this.controlLayerLeft.style.height = 0;
        this.controlLayerLeft.style.width = 0;
        this.controlLayerLeft.style.top = 0;
        this.controlLayerLeft.style.left = 0;
        if (isTransparent) {
            this.controlLayerUp.style.opacity = 0;
        }
    }

    /**
     * set controlLayers positions
     */
    Tutorial.prototype.setControlLayer = function setControlLayer(element) {
        var pos;
        if (typeof element !== 'object') {
            return;
        }
        this.controlLayerUp.style.opacity = 0.4;
        pos = element.getBoundingClientRect();
        //up
        this.controlLayerUp.style.height = pos.top + 'px';
        this.controlLayerUp.style.width = '100%';
        //down
        this.controlLayerDown.style.top = (pos.top + pos.height) + 'px';
        this.controlLayerDown.style.width = '100%';
        this.controlLayerDown.style.height = '100%';
        //right
        this.controlLayerRight.style.left = (pos.left + pos.width) + 'px';
        this.controlLayerRight.style.top = pos.top + 'px';
        this.controlLayerRight.style.height = pos.height + 'px';
        this.controlLayerRight.style.width = '100%';
        //left
        this.controlLayerLeft.style.width = pos.left + 'px';
        this.controlLayerLeft.style.height = pos.height + 'px';
        this.controlLayerLeft.style.top = pos.top + 'px';
    };

    /**
     * find the element that content the text
     */
    Tutorial.prototype.findElementByTextContent = function findElementByTextContent(nodes, text) {
        var i;
        for (i = 0; i < nodes.length; i ++) {
            if (nodes[i].textContent() == text) {
                return nodes[i];
            }
        }
        return null;
    }

    /**
     * Destroy
     */
    Tutorial.prototype.destroy = function destroy() {
        var stepActivePos, i;

        stepActivePos = this.steps.indexOf(this.stepActive);
        for (i = stepActivePos; i < this.steps.length; i ++) {
            this.steps[i].destroy();
        }
        document.body.removeChild(this.controlLayer);
        document.body.removeChild(this.msgLayer);
        this.controlLayer = null;
        this.msgLayer = null;
        this.steps = null;
    };

    /*************************************************************************
     * Make Tutorial public
     *************************************************************************/
    Wirecloud.ui.Tutorial = Tutorial;
})();
<commit_msg>Remove getTutorial usage<commit_after>/*
 *     (C) Copyright 2012 Universidad Politécnica de Madrid
 *
 *     This file is part of Wirecloud Platform.
 *
 *     Wirecloud Platform is free software: you can redistribute it and/or
 *     modify it under the terms of the GNU Affero General Public License as
 *     published by the Free Software Foundation, either version 3 of the
 *     License, or (at your option) any later version.
 *
 *     Wirecloud is distributed in the hope that it will be useful, but WITHOUT
 *     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 *     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public
 *     License for more details.
 *
 *     You should have received a copy of the GNU Affero General Public License
 *     along with Wirecloud Platform.  If not, see
 *     <http://www.gnu.org/licenses/>.
 *
 */

/*global Wirecloud*/

(function () {

    "use strict";

    /*************************************************************************
     * Constructor
     *************************************************************************/
    var Tutorial = function Tutorial(instructions) {
        var i, key;

        this.stepActive = null;
        this.steps = [];

        this.controlLayer = document.createElement("div");
        this.controlLayerUp = document.createElement("div");
        this.controlLayerDown = document.createElement("div");
        this.controlLayerLeft = document.createElement("div");
        this.controlLayerRight = document.createElement("div");
        this.controlLayer.addClassName("controlLayer");
        this.controlLayerUp.addClassName("controlLayerUp");
        this.controlLayerDown.addClassName("controlLayerDown");
        this.controlLayerLeft.addClassName("controlLayerLeft");
        this.controlLayerRight.addClassName("controlLayerRight");
        this.controlLayer.appendChild(this.controlLayerUp);
        this.controlLayer.appendChild(this.controlLayerDown);
        this.controlLayer.appendChild(this.controlLayerLeft);
        this.controlLayer.appendChild(this.controlLayerRight);

        document.body.appendChild(this.controlLayer);
        this.resetControlLayer();

        this.msgLayer = document.createElement("div");
        this.msgLayer.addClassName("msgLayer");
        document.body.appendChild(this.msgLayer);

        this.instructions = instructions;

        var mapping = {
            'simpleDescription': Wirecloud.ui.Tutorial.SimpleDescription,
            'userAction': Wirecloud.ui.Tutorial.UserAction,
            'formAction': Wirecloud.ui.Tutorial.FormAction,
            'autoAction': Wirecloud.ui.Tutorial.AutoAction,
        };

        // creating simpleDescriptions
        for (i = 0; i < this.instructions.length; i ++) {
            var constructor = mapping[this.instructions[i].type];
            this.steps[i] = new constructor(this, this.instructions[i]);

            if (i == 0) {
                this.steps[i].wrapperElement.addClassName("activeStep");
                this.stepActive = this.steps[i];
            }
            if (i == this.instructions.length-1) {
                this.steps[i].setLast();
            } else {
                this.steps[i].setNext();
            }
        }
    };

    /**
     * Next Step
     */
    Tutorial.prototype.nextStep = function nextStep() {
        var order;

        order = this.steps.indexOf(this.stepActive );
        if (order < this.steps.length) {
            this.stepActive.destroy();
            this.resetControlLayer(false);
            this.stepActive = this.steps[this.steps.indexOf(this.stepActive) + 1];
            this.stepActive.activate();
        } else {
            this.destroy;
        }
    };

    /**
     * reset controlLayers positions
     */
    Tutorial.prototype.resetControlLayer = function resetControlLayer(isTransparent) {
        this.controlLayerUp.style.opacity = 0.4;
        //up
        this.controlLayerUp.style.height = '100%';
        this.controlLayerUp.style.width = '100%';
        this.controlLayerUp.style.top = 0;
        this.controlLayerUp.style.left = 0;
        //down
        this.controlLayerDown.style.height = 0;
        this.controlLayerDown.style.width = 0;
        this.controlLayerDown.style.top = 0;
        this.controlLayerDown.style.left = 0;
        //right
        this.controlLayerRight.style.height = 0;
        this.controlLayerRight.style.width = 0;
        this.controlLayerRight.style.top = 0;
        this.controlLayerRight.style.left = 0;
        //left
        this.controlLayerLeft.style.height = 0;
        this.controlLayerLeft.style.width = 0;
        this.controlLayerLeft.style.top = 0;
        this.controlLayerLeft.style.left = 0;
        if (isTransparent) {
            this.controlLayerUp.style.opacity = 0;
        }
    }

    /**
     * set controlLayers positions
     */
    Tutorial.prototype.setControlLayer = function setControlLayer(element) {
        var pos;
        if (typeof element !== 'object') {
            return;
        }
        this.controlLayerUp.style.opacity = 0.4;
        pos = element.getBoundingClientRect();
        //up
        this.controlLayerUp.style.height = pos.top + 'px';
        this.controlLayerUp.style.width = '100%';
        //down
        this.controlLayerDown.style.top = (pos.top + pos.height) + 'px';
        this.controlLayerDown.style.width = '100%';
        this.controlLayerDown.style.height = '100%';
        //right
        this.controlLayerRight.style.left = (pos.left + pos.width) + 'px';
        this.controlLayerRight.style.top = pos.top + 'px';
        this.controlLayerRight.style.height = pos.height + 'px';
        this.controlLayerRight.style.width = '100%';
        //left
        this.controlLayerLeft.style.width = pos.left + 'px';
        this.controlLayerLeft.style.height = pos.height + 'px';
        this.controlLayerLeft.style.top = pos.top + 'px';
    };

    /**
     * find the element that content the text
     */
    Tutorial.prototype.findElementByTextContent = function findElementByTextContent(nodes, text) {
        var i;
        for (i = 0; i < nodes.length; i ++) {
            if (nodes[i].textContent() == text) {
                return nodes[i];
            }
        }
        return null;
    }

    /**
     * Destroy
     */
    Tutorial.prototype.destroy = function destroy() {
        var stepActivePos, i;

        stepActivePos = this.steps.indexOf(this.stepActive);
        for (i = stepActivePos; i < this.steps.length; i ++) {
            this.steps[i].destroy();
        }
        document.body.removeChild(this.controlLayer);
        document.body.removeChild(this.msgLayer);
        this.controlLayer = null;
        this.msgLayer = null;
        this.steps = null;
    };

    /*************************************************************************
     * Make Tutorial public
     *************************************************************************/
    Wirecloud.ui.Tutorial = Tutorial;
})();
<|endoftext|>


<commit_before>/**
 * Adapted from bootstrap-growl (https://github.com/ifightcrime/bootstrap-growl)
 */

((function (root, factory) {

    // CommonJS
    if (typeof exports === 'object') {
        module.exports = factory(require('jquery', 'bootstrap'));
    }
    // AMD module
    else if (typeof define === 'function' && define.amd) {
        define(['jquery', 'bootstrap'], factory);
    }

})(this, function ($) {
    $.bootstrapGrowl = function (message, options) {
        var $alert, css, offsetAmount;

        options = $.extend({}, $.bootstrapGrowl.default_options, options);
        $alert = $("
");
        $alert.attr("class", "bootstrap-growl alert");
        if (options.type) {
            $alert.addClass("alert-" + options.type);
        }
        if (options.allow_dismiss) {
            $alert.append('×');
        }
        $alert.append(message);

        var mobile = $(window).width() <= 767;

        if (mobile) {
            offsetAmount = 63;
        } else {
            offsetAmount = -10;
        }
        $(".bootstrap-growl").each(function() {
            return offsetAmount = Math.max(offsetAmount, parseInt($(this).css('top')) + $(this).outerHeight() + options.stackup_spacing);
        });
        css = {
            "position": mobile ? "fixed" : "absolute",
            "margin": "0",
            "z-index": 9999,
            "display": "none",
            "width": options.width,
            "max-width": $(window).width() - 50,
            "top": offsetAmount + "px",
            "right": "25px"
        };
        $alert.css(css);
        $(options.ele).append($alert);
        $alert.fadeIn();
        if (options.delay > 0) {
            return $alert.delay(options.delay).fadeOut(function () {
                return $(this).remove();
            });
        }
    };

    $.bootstrapGrowl.default_options = {
        ele: "body",
        type: null,
        align: "right",
        width: "100%",
        delay: 4000,
        allow_dismiss: true,
        stackup_spacing: 10
    };

}));
<commit_msg>Added a couple of missing copyrights<commit_after>
 /*!
  * Copyright 2016,  Digital Reasoning
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  *
*/
/**
 * Adapted from bootstrap-growl (https://github.com/ifightcrime/bootstrap-growl)
 */

((function (root, factory) {

    // CommonJS
    if (typeof exports === 'object') {
        module.exports = factory(require('jquery', 'bootstrap'));
    }
    // AMD module
    else if (typeof define === 'function' && define.amd) {
        define(['jquery', 'bootstrap'], factory);
    }

})(this, function ($) {
    $.bootstrapGrowl = function (message, options) {
        var $alert, css, offsetAmount;

        options = $.extend({}, $.bootstrapGrowl.default_options, options);
        $alert = $("
");
        $alert.attr("class", "bootstrap-growl alert");
        if (options.type) {
            $alert.addClass("alert-" + options.type);
        }
        if (options.allow_dismiss) {
            $alert.append('×');
        }
        $alert.append(message);

        var mobile = $(window).width() <= 767;

        if (mobile) {
            offsetAmount = 63;
        } else {
            offsetAmount = -10;
        }
        $(".bootstrap-growl").each(function() {
            return offsetAmount = Math.max(offsetAmount, parseInt($(this).css('top')) + $(this).outerHeight() + options.stackup_spacing);
        });
        css = {
            "position": mobile ? "fixed" : "absolute",
            "margin": "0",
            "z-index": 9999,
            "display": "none",
            "width": options.width,
            "max-width": $(window).width() - 50,
            "top": offsetAmount + "px",
            "right": "25px"
        };
        $alert.css(css);
        $(options.ele).append($alert);
        $alert.fadeIn();
        if (options.delay > 0) {
            return $alert.delay(options.delay).fadeOut(function () {
                return $(this).remove();
            });
        }
    };

    $.bootstrapGrowl.default_options = {
        ele: "body",
        type: null,
        align: "right",
        width: "100%",
        delay: 4000,
        allow_dismiss: true,
        stackup_spacing: 10
    };

}));
<|endoftext|>


<commit_before>/*
#     CloudBoost - Core Engine that powers Bakend as a Service
#     (c) 2014 HackerBay, Inc.
#     CloudBoost may be freely distributed under the Apache 2 License
*/

module.exports = function (io) {

    var g = {};
    io.use(function (socket, next) {
        next();
    });
    io.on('connection', function (socket) {

        try {
            socket.on('app-init', function (data) {
                try {
                    socket.join(data);
                } catch (e) {
                    global.winston.log('error', {
                        "error": String(e),
                        "stack": new Error().stack
                    });
                }
            });

            /* Custom Channel Listeners. */

            socket.on('join-custom-channel', function (data) {
                try {
                    console.log('++++++++ Joined Realtime Channel+++++');
                    console.log(data);
                    socket.join(data);

                } catch (e) {
                    global.winston.log('error', {
                        "error": String(e),
                        "stack": new Error().stack
                    });
                }
            });

            socket.on('socket-disconnect', function (data) {
                try {
                    socket.disconnect();
                } catch (e) {
                    global.winston.log('error', {
                        "error": String(e),
                        "stack": new Error().stack
                    });
                }
            });

            socket.on('leave-custom-channel', function (data) {
                try {
                    console.log('++++++++ Left Realtime Channel+++++');
                    console.log(data);
                    socket.leave(data);
                } catch (e) {
                    global.winston.log('error', {
                        "error": String(e),
                        "stack": new Error().stack
                    });
                }
            });

            socket.on('publish-custom-channel', function (data) {
                try {
                    console.log('++++++++ Publish Realtime Channel+++++');
                    console.log(data);
                    //if this doucment is an instance of a table Object.
                    var roomSockets = io.to(data.channel);
                    var sockets = roomSockets.sockets;

                    if (typeof sockets === "object") {
                        for (var key in sockets) {
                            if (sockets[key]) {
                                sockets[key].emit(data.channel, data.data);
                            }
                        }
                    }

                    io.emit(data.channel, data.data);

                } catch (e) {
                    global.winston.log('error', {
                        "error": String(e),
                        "stack": new Error().stack
                    });
                }
            });

            /* CloudObject Channel Listeners. */
            socket.on('join-object-channel', function (data) {
                try {
                    console.log('++++++++ Joined Object Realtime Channel+++++');
                    console.log(data);

                    if (typeof data === 'string') { // Backward Compatibility : data only has the room id
                        socket.join(data);
                    } else { //data has both the room id and the sessionId.
                        socket.join(data.room);
                        //connect socket.id and sessionId together

                        // build socketid specefic to table
                        var tableSocketId = data.room.split('')
                        tableSocketId.splice(-8,8)
                        tableSocketId = socket.id + tableSocketId.join('')

                        global.socketQueryHelper.setData(tableSocketId, data.data);
                        global.socketSessionHelper.saveSession(socket.id, data.sessionId);
                    }
                } catch (e) {
                    global.winston.log('error', {
                        "error": String(e),
                        "stack": new Error().stack
                    });
                }
            });

            socket.on('leave-object-channel', function (data) {
                try {
                    console.log('++++++++ Leave Object Realtime Channel+++++');
                    console.log(data);
                    // build socketid specefic to table
                    var tableSocketId = socket.id + data.event
                    global.socketQueryHelper.getData(tableSocketId, data.eventType, function (err, socketData) {
                        if (err)
                            throw err;
                        else {
                            socket.leave(data.event + socketData.timestamp);
                            socket.emit('leave' + data.event + data.timestamp, socketData.timestamp); //to removeAlListeners
                            global.socketQueryHelper.deleteData(tableSocketId, data.event);
                        }
                    });
                } catch (e) {
                    global.winston.log('error', {
                        "error": String(e),
                        "stack": new Error().stack
                    });
                }
            });

            socket.on('disconnect', function () {
                try {
                    global.socketSessionHelper.deleteSession(socket.id); //deletes the lnk between this socket and session.
                } catch (e) {
                    global.winston.log('error', {
                        "error": String(e),
                        "stack": new Error().stack
                    });
                }
            });

        } catch (e) {
            global.winston.log('error', {
                "error": String(e),
                "stack": new Error().stack
            });
        }

    });

    g.sendObjectNotification = function (appId, document, eventType) {
        try {
            //event type can be created, updated, deleted.
            if (document && document._tableName) {
                console.log('++++++++ Sending Realtime Object Notification+++++');
                console.log(eventType + ' event');
                console.log(document);
                //if this doucment is an instance of a table Object.
                var roomSockets = io.to(appId.toLowerCase() + 'table' + document._tableName.toLowerCase() + eventType.toLowerCase());
                var sockets = roomSockets.sockets;

                var promises = [];

                //check for ACL and then send.

                if (typeof sockets === "object") {
                    for (var key in sockets) {
                        if (sockets[key]) {
                            promises.push(_sendNotification(appId, document, sockets[key], eventType));
                        }
                    }
                } else {
                    for (var i = 0; i < sockets.length; i++) {
                        var socket = sockets[i];
                        promises.push(_sendNotification(appId, document, socket, eventType));
                    }
                }

                global.q.all(promises).then(function () {
                    console.log("Notifications Sent");
                }, function () {
                    console.log("Error on sending Notifications");
                });
            }
        } catch (e) {
            global.winston.log('error', {
                "error": String(e),
                "stack": new Error().stack
            });
        }
    };

    return g;

};

/**
 */

function _sendNotification(appId, document, socket, eventType) {
    var deferred = global.q.defer();
    try {
        global.socketSessionHelper.getSession(socket.id, function (err, session) {
            if (err) {
                deferred.reject();
            }

            session = session || {}

            global.socketQueryHelper.getData(_buildSocketId(socket.id,appId,document._tableName,eventType), eventType, function (err, socketData) {

                socketData = socketData || { timestamp: '' };
                var socketQueryValidate = true;
                if (socketData.query) {
                    socketQueryValidate = global.socketQueryHelper.validateSocketQuery(document, socketData.query.query);
                }

                if (socketQueryValidate) {
                    // check if public access is enabled or the current session user is allowed
                    if (global.aclHelper.isAllowedReadAccess(session.userId, session.roles, document.ACL)) {
                        console.log(appId.toLowerCase() + 'table' + document._tableName.toLowerCase() + eventType.toLowerCase() + socketData.timestamp)
                        socket.emit(appId.toLowerCase() + 'table' + document._tableName.toLowerCase() + eventType.toLowerCase() + socketData.timestamp, JSON.stringify(document));
                        console.log("Socket Emited.", document);
                        deferred.resolve();
                    } else {
                        // if no access then only emit if listen is using master key
                        if (socketData.appKey) {
                            global.appService.isMasterKey(appId, socketData.appKey).then(( isMaster ) => {
                                if(isMaster){
                                    console.log(appId.toLowerCase() + 'table' + document._tableName.toLowerCase() + eventType.toLowerCase() + socketData.timestamp)
                                    socket.emit(appId.toLowerCase() + 'table' + document._tableName.toLowerCase() + eventType.toLowerCase() + socketData.timestamp, JSON.stringify(document));
                                    console.log("Socket Emited.", document);
                                }
                                deferred.resolve();
                            })
                        } else {
                            console.log('Socket doesnt have access to the emitted data');
                            deferred.resolve();
                        }
                    }

                } else {
                    console.log('Socket Query doesn\'t satsfies the current document');
                    deferred.resolve();
                }

            });
        });
    } catch (e) {
        global.winston.log('error', {
            "error": String(e),
            "stack": new Error().stack
        });
        deferred.reject(e);
    }
    return deferred.promise;
}

function _buildSocketId(socketId, appId,tableName,eventType){
    return socketId + (appId + 'table' + tableName + eventType).toLowerCase()
}
<commit_msg>fix realtime duplicate events<commit_after>/*
#     CloudBoost - Core Engine that powers Bakend as a Service
#     (c) 2014 HackerBay, Inc.
#     CloudBoost may be freely distributed under the Apache 2 License
*/

module.exports = function (io) {

    var g = {};
    io.use(function (socket, next) {
        next();
    });
    io.on('connection', function (socket) {

        try {
            socket.on('app-init', function (data) {
                try {
                    socket.join(data);
                } catch (e) {
                    global.winston.log('error', {
                        "error": String(e),
                        "stack": new Error().stack
                    });
                }
            });

            /* Custom Channel Listeners. */

            socket.on('join-custom-channel', function (data) {
                try {
                    console.log('++++++++ Joined Realtime Channel+++++');
                    console.log(data);
                    socket.join(data);

                } catch (e) {
                    global.winston.log('error', {
                        "error": String(e),
                        "stack": new Error().stack
                    });
                }
            });

            socket.on('socket-disconnect', function (data) {
                try {
                    socket.disconnect();
                } catch (e) {
                    global.winston.log('error', {
                        "error": String(e),
                        "stack": new Error().stack
                    });
                }
            });

            socket.on('leave-custom-channel', function (data) {
                try {
                    console.log('++++++++ Left Realtime Channel+++++');
                    console.log(data);
                    socket.leave(data);
                } catch (e) {
                    global.winston.log('error', {
                        "error": String(e),
                        "stack": new Error().stack
                    });
                }
            });

            socket.on('publish-custom-channel', function (data) {
                try {
                    console.log('++++++++ Publish Realtime Channel+++++');
                    console.log(data);
                    //if this doucment is an instance of a table Object.
                    var roomSockets = io.to(data.channel);
                    var sockets = roomSockets.sockets;

                    // if (typeof sockets === "object") {
                    //     for (var key in sockets) {
                    //         if (sockets[key]) {
                    //             sockets[key].emit(data.channel, data.data);
                    //         }
                    //     }
                    // }

                    io.emit(data.channel, data.data);

                } catch (e) {
                    global.winston.log('error', {
                        "error": String(e),
                        "stack": new Error().stack
                    });
                }
            });

            /* CloudObject Channel Listeners. */
            socket.on('join-object-channel', function (data) {
                try {
                    console.log('++++++++ Joined Object Realtime Channel+++++');
                    console.log(data);

                    if (typeof data === 'string') { // Backward Compatibility : data only has the room id
                        socket.join(data);
                    } else { //data has both the room id and the sessionId.
                        socket.join(data.room);
                        //connect socket.id and sessionId together

                        // build socketid specefic to table
                        var tableSocketId = data.room.split('')
                        tableSocketId.splice(-8,8)
                        tableSocketId = socket.id + tableSocketId.join('')

                        global.socketQueryHelper.setData(tableSocketId, data.data);
                        global.socketSessionHelper.saveSession(socket.id, data.sessionId);
                    }
                } catch (e) {
                    global.winston.log('error', {
                        "error": String(e),
                        "stack": new Error().stack
                    });
                }
            });

            socket.on('leave-object-channel', function (data) {
                try {
                    console.log('++++++++ Leave Object Realtime Channel+++++');
                    console.log(data);
                    // build socketid specefic to table
                    var tableSocketId = socket.id + data.event
                    global.socketQueryHelper.getData(tableSocketId, data.eventType, function (err, socketData) {
                        if (err)
                            throw err;
                        else {
                            socket.leave(data.event + socketData.timestamp);
                            socket.emit('leave' + data.event + data.timestamp, socketData.timestamp); //to removeAlListeners
                            global.socketQueryHelper.deleteData(tableSocketId, data.event);
                        }
                    });
                } catch (e) {
                    global.winston.log('error', {
                        "error": String(e),
                        "stack": new Error().stack
                    });
                }
            });

            socket.on('disconnect', function () {
                try {
                    global.socketSessionHelper.deleteSession(socket.id); //deletes the lnk between this socket and session.
                } catch (e) {
                    global.winston.log('error', {
                        "error": String(e),
                        "stack": new Error().stack
                    });
                }
            });

        } catch (e) {
            global.winston.log('error', {
                "error": String(e),
                "stack": new Error().stack
            });
        }

    });

    g.sendObjectNotification = function (appId, document, eventType) {
        try {
            //event type can be created, updated, deleted.
            if (document && document._tableName) {
                console.log('++++++++ Sending Realtime Object Notification+++++');
                console.log(eventType + ' event');
                console.log(document);
                //if this doucment is an instance of a table Object.
                var roomSockets = io.to(appId.toLowerCase() + 'table' + document._tableName.toLowerCase() + eventType.toLowerCase());
                var sockets = roomSockets.sockets;

                var promises = [];

                //check for ACL and then send.

                if (typeof sockets === "object") {
                    for (var key in sockets) {
                        if (sockets[key]) {
                            promises.push(_sendNotification(appId, document, sockets[key], eventType));
                        }
                    }
                } else {
                    for (var i = 0; i < sockets.length; i++) {
                        var socket = sockets[i];
                        promises.push(_sendNotification(appId, document, socket, eventType));
                    }
                }

                global.q.all(promises).then(function () {
                    console.log("Notifications Sent");
                }, function () {
                    console.log("Error on sending Notifications");
                });
            }
        } catch (e) {
            global.winston.log('error', {
                "error": String(e),
                "stack": new Error().stack
            });
        }
    };

    return g;

};

/**
 */

function _sendNotification(appId, document, socket, eventType) {
    var deferred = global.q.defer();
    try {
        global.socketSessionHelper.getSession(socket.id, function (err, session) {
            if (err) {
                deferred.reject();
            }

            session = session || {}

            global.socketQueryHelper.getData(_buildSocketId(socket.id,appId,document._tableName,eventType), eventType, function (err, socketData) {

                socketData = socketData || { timestamp: '' };
                var socketQueryValidate = true;
                if (socketData.query) {
                    socketQueryValidate = global.socketQueryHelper.validateSocketQuery(document, socketData.query.query);
                }

                if (socketQueryValidate) {
                    // check if public access is enabled or the current session user is allowed
                    if (global.aclHelper.isAllowedReadAccess(session.userId, session.roles, document.ACL)) {
                        console.log(appId.toLowerCase() + 'table' + document._tableName.toLowerCase() + eventType.toLowerCase() + socketData.timestamp)
                        socket.emit(appId.toLowerCase() + 'table' + document._tableName.toLowerCase() + eventType.toLowerCase() + socketData.timestamp, JSON.stringify(document));
                        console.log("Socket Emited.", document);
                        deferred.resolve();
                    } else {
                        // if no access then only emit if listen is using master key
                        if (socketData.appKey) {
                            global.appService.isMasterKey(appId, socketData.appKey).then(( isMaster ) => {
                                if(isMaster){
                                    console.log(appId.toLowerCase() + 'table' + document._tableName.toLowerCase() + eventType.toLowerCase() + socketData.timestamp)
                                    socket.emit(appId.toLowerCase() + 'table' + document._tableName.toLowerCase() + eventType.toLowerCase() + socketData.timestamp, JSON.stringify(document));
                                    console.log("Socket Emited.", document);
                                }
                                deferred.resolve();
                            })
                        } else {
                            console.log('Socket doesnt have access to the emitted data');
                            deferred.resolve();
                        }
                    }

                } else {
                    console.log('Socket Query doesn\'t satsfies the current document');
                    deferred.resolve();
                }

            });
        });
    } catch (e) {
        global.winston.log('error', {
            "error": String(e),
            "stack": new Error().stack
        });
        deferred.reject(e);
    }
    return deferred.promise;
}

function _buildSocketId(socketId, appId,tableName,eventType){
    return socketId + (appId + 'table' + tableName + eventType).toLowerCase()
}
<|endoftext|>


<commit_before>var $ = require("jquery")
var _ = require("lodash")
var Rx = require("rx")
require("rx-jquery")

var parseValidationResult = function(n) {
  function toNext(x) { return new Rx.Notification.createOnNext(x) }
  function parseError () {
      try {
        return toNext({ success: false, message: $.parseJSON(n.value.jqXHR.responseText)['message'] })
      } catch (e) { return toNext({ success: false }) }
  }

  switch (n.kind) {
    case 'E':
      return parseError()
    case 'N': {
      if (n.value.jqXHR.status == 200 && n.value.data.success !== false) return toNext(n.value.data)
      else return parseError()
    }
    default : return n
  }
}

function validate(field, dist) {
  return Rx.Observable.onErrorResumeNext(
    $.getJSONAsObservable('/rest/v1/validate/' + field + '/' + encodeURIComponent(dist))
      .materialize()
      .select(parseValidationResult)
      .dematerialize()
  )
}

function toggle(field, distValidationResult) {
  $("#" + field).toggleClass("hasError", !distValidationResult.success)

  $("#" + field + "-logo").toggle(distValidationResult.success)
  $("#" + field + "-text").toggle(distValidationResult.success)
  if (distValidationResult.success)
    $("#" + field + "-text").text(distValidationResult[field])
}

function createValidatable(field, saves) {

  var changes = $("#ex-" + field).onAsObservable('keyup change')
    .map( function (ev) { return $(ev.target).val() })
    .filter( function(val) { return val.length > 0 })
    .throttle(300)
    .distinctUntilChanged()
    .repeat()

  var validations = changes.flatMapLatest(_.partial(validate, field))
  validations.subscribe(_.partial(toggle, field))

  validations.sample(saves).subscribe(function (v) { $("#ex-" + field).val(v[field]).change() })

  return validations.map(function(res) { return res.success })
}

exports.create = function() {
  var saves = $("#details-save").onAsObservable("click")
  var distance = createValidatable("distance", saves)
  var time = createValidatable("time", saves)

  saves.subscribe(function() {
    $("#details-dialog").hide()
  })

  $("#show-details-dialog").onAsObservable("click").subscribe(function() {
    $("#details-dialog").show()
  })

  return {
    distance: distance,
    time: time
  }
}
<commit_msg>update validation urls according to the new backend<commit_after>var $ = require("jquery")
var _ = require("lodash")
var Rx = require("rx")
require("rx-jquery")

var parseValidationResult = function(n) {
  function toNext(x) { return new Rx.Notification.createOnNext(x) }
  function parseError () {
      try {
        return toNext({ success: false, message: $.parseJSON(n.value.jqXHR.responseText)['message'] })
      } catch (e) { return toNext({ success: false }) }
  }

  switch (n.kind) {
    case 'E':
      return parseError()
    case 'N': {
      if (n.value.jqXHR.status == 200 && n.value.data.success !== false) return toNext(n.value.data)
      else return parseError()
    }
    default : return n
  }
}

function validate(field, dist) {
  return Rx.Observable.onErrorResumeNext(
    $.getJSONAsObservable('/trail/rest/validate/' + field + '/' + encodeURIComponent(dist))
      .materialize()
      .select(parseValidationResult)
      .dematerialize()
  )
}

function toggle(field, distValidationResult) {
  $("#" + field).toggleClass("hasError", !distValidationResult.success)

  $("#" + field + "-logo").toggle(distValidationResult.success)
  $("#" + field + "-text").toggle(distValidationResult.success)
  if (distValidationResult.success)
    $("#" + field + "-text").text(distValidationResult[field])
}

function createValidatable(field, saves) {

  var changes = $("#ex-" + field).onAsObservable('keyup change')
    .map( function (ev) { return $(ev.target).val() })
    .filter( function(val) { return val.length > 0 })
    .throttle(300)
    .distinctUntilChanged()
    .repeat()

  var validations = changes.flatMapLatest(_.partial(validate, field))
  validations.subscribe(_.partial(toggle, field))

  validations.sample(saves).subscribe(function (v) { $("#ex-" + field).val(v[field]).change() })

  return validations.map(function(res) { return res.success })
}

exports.create = function() {
  var saves = $("#details-save").onAsObservable("click")
  var distance = createValidatable("distance", saves)
  var time = createValidatable("time", saves)

  saves.subscribe(function() {
    $("#details-dialog").hide()
  })

  $("#show-details-dialog").onAsObservable("click").subscribe(function() {
    $("#details-dialog").show()
  })

  return {
    distance: distance,
    time: time
  }
}
<|endoftext|>


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

/**
 * The Saiku Splash Screen
 */
var SplashScreen = Backbone.View.extend({
    events: {
        'click .run_query'      : 'run_query',
        'click .run_dashboards' : 'run_dashboard',
        'click .head'           : 'click_head',
        'click .beg_tut'        : 'run_tour'
    },

    template: _.template(
        '
' +
            '' +
                '
' +
                    '
Welcome
' +
                    '
Features
' +
                    '
Get Help
' +
                    '
Enterprise
' +
                '
' +
                '
Explore Data. Visualise. Act.
' +
            '' +
            '
' +
                '
' +
                    '
' +
                        '
Saiku
' +
                        '
Saiku has the power to change the way you think about your business and make decisions. Saiku provides powerful, web based analytics for everyone in your organisation. Quickly and easily analyse data from any data source to discover what is really happening inside and outside your organisation.
' +
                        '
Quick Links
' +
                        '
' +
                            '
Create a new query
' +
                            '
Create a dashboard
' +
                            '
 Visit the website
' +
                            '
Tutorials
' +
                        '
' +
                        '
Get Enterprise
' +
                    '
' +
                    '
' +
                        '
Discover more about Saiku
' +
                        '
Saiku Analytics provides both a Community Version and an Enterprise Version with added features. To find out more you can visit our website or watch the videos on our Youtube channel.
' +
                        '
If you are using Saiku Analytics in a business or commercial product, you can help give back in many ways. Swing by our IRC channel and help foster the community, join the mailing lists and ask/answer questions, sponsor a new feature, or best of all purchase an EE license, which funds development of Saiku Community Edition along with Enterprise Edition.
' +
                    '
' +
                '
' +
                '
' +
                    '
Saiku
' +
                    '
Features
' +
                    '
Web Based Analysis
' +
                    '
Saiku provides the user with an entirely browser based experience. We support all modern browsers, and our user interface is 100% HTML and Javascript.
Saiku uses REST based communications, this allows the development of custom user interfaces and facilitates the easy integration of the Saiku Server into other applications and services.
' +
                    '
Standards Compliant
' +
                    '
Saiku is based upon the Microsoft MDX query language and will work on most JDBC compliant data sources. We also provide a number of connectors to NOSQL data sources.
' +
                    '
Dynamic charting
' +
                    '
Saiku uses a flexible charting engine to provide a wide range of charts and graphs. These are all HTML & Javascript only and don\'t require flash to be installed on the computer.
' +
                    '
Pluggable visualisation engine
' +
                    '
Saiku Enterprise boasts a fully pluggable visualisation engine. This allows developers to build third party extensions and plug them into Saiku Enterprise to extend or replace the existing visualisations.
' +
                '
' +
                '
' +
                    '
Saiku
' +
                    '
Help
' +
                    '
We provide Training, Consulting and Support to ensure you get the most from Saiku and your data. Our services cover all aspects of data analysis including data strategy, design, architecture, deployment and application/software support.
' +
                    '
' +
                        '
' +
                            'Tutorials	' +
                            'Docs	' +
                            'Support	' +
                        '
' +
                        '
' +
                            'We have a number of click through tutorials to help get your started:' +
                                '
' +
                                    '
Beginners (Query building and charts)
' +
                                '
' +
                            '	' +
                            'Why not try  our new Documentation site
for community documentation.	' +
                            'If you require more,
contact us for support.	' +
                        '
' +
                    '
' +
                '
' +
                '
' +
                    '
Saiku
' +
                    '
Enterprise
' +
                    '
Saiku Enterprise is our fully supported and tested server and Pentaho plugin system. Buy Saiku Enterprise from as little as $15 per user per month and enjoy the addtional features Saiku Enterprise has to offer!
' +
                    '
To find out more visit our site or schedule a call with one of us and we can show you why you should choose Saiku Enterprise!
' +
                '
' +
            '
' +
        '
'
    ),

    initialize: function(args) {
        _.bindAll(this, 'caption');
        _.extend(this, Backbone.Events);
    },

    caption: function(increment) {
        return 'Home';
    },

    render: function() {
        this.$el.html(this.template());

        if (
            Settings.LICENSE &&
            Settings.LICENSE.licenseType !== undefined &&
            Settings.LICENSE.licenseType !== 'trial' &&
            Settings.LICENSE.licenseType !== 'Open Source License'
        ) {
            this.$el.find('.enterprisetoggle').css('visibility', 'hidden');
        }

        this.getContent();
        this.setupPage();

        $('#splash > nav > ul > li.active > a').click(function() {
            var active = $(this).attr('class');
            $('nav li').removeClass('active');
            $(this).parent().addClass('active');
            $('.stabs section').hide();
            $('#' + active).fadeIn();
        });

        return this;
    },

    click_head: function(event) {
        event.preventDefault();

        var target = event.target;
        var a = $(target).attr('class').split(' ');

        $('nav li').removeClass('active');
        $(target).parent().addClass('active');
        $('.stabs section').hide();

        var active = '';
        if (a.indexOf('welcome') > -1) {
            active = 'welcome';
        }
        else if (a.indexOf('features') > -1) {
            active = 'features';
        }
        else if (a.indexOf('help') > -1) {
            active = 'help';
        }
        else if (a.indexOf('enterprise') > -1) {
            active = 'enterprise';
        }

        $('#' + active).fadeIn();
    },

    run_tour: function() {
        this.toolbar = Saiku.toolbar;

        var tour = new Tour({ toolbar: this.toolbar });

        tour.run_tour();
    },

    run_query: function() {
        Saiku.tabs.add(new Workspace());

        return false;
    },

    run_dashboard: function() {
        if (Saiku.Dashboards === undefined) {
            alert('Please upgrade to Saiku Enterprise for Dashboards');
        }
        else {
            var tab = _.find(Saiku.tabs._tabs, function(tab) {
                return tab.content instanceof Dashboards;
            });

            if (tab) {
                tab.select();
            }
            else {
                Saiku.tabs.add(new Dashboards());
            }

            return false;
        }

        return false;
    },

    setupPage: function() {
        var height = $(window).height();
        var active = $('nav li.active a').attr('class');

        $('body').height(height);
        $('.stabs section').each(function() {
            var vH = $(this).height();
            var dif = (height - vH) / 2 - 50;

            if (dif < 0) {
                dif = 20;
            }
        });

        $('#' + active).fadeIn();
    },

    getContent: function() {
        var self = this;

        $.ajax({
            type: 'GET',
            url: 'http://meteorite.bi/content.json',
            async: false,
            contentType: 'application/json',
            dataType: 'jsonp',
            jsonpCallback: 'jsonCallback2',
            cache: true,
            success: function(json) {
                // self.$el.find('#dyn_content').html(json.item[0].content);
                self.$el.find('.responsive-container').fitVids();
                self.$el.html(self.template());

                if (
                    Settings.LICENSE &&
                    Settings.LICENSE.licenseType !== 'trial' &&
                    Settings.LICENSE.licenseType !== 'Open Source License'
                ) {
                    self.$el.find('.enterprisetoggle').css('visibility', 'hidden');
                }
            },
            error: function(e) {
                self.$el.html(self.template());

                if (
                    Settings.LICENSE &&
                    Settings.LICENSE.licenseType !== 'trial' &&
                    Settings.LICENSE.licenseType !== 'Open Source License'
                ) {
                    self.$el.find('.enterprisetoggle').css('visibility', 'hidden');
                }
            }
        });
    }
});
<commit_msg>Update SplashScreen.js<commit_after>/*
 * Copyright 2014 OSBI Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * The Saiku Splash Screen
 */
var SplashScreen = Backbone.View.extend({
    events: {
        'click .run_query'      : 'run_query',
        'click .run_dashboards' : 'run_dashboard',
        'click .head'           : 'click_head',
        'click .beg_tut'        : 'run_tour'
    },

    template: _.template(
        '
' +
            '' +
                '
' +
                    '
Welcome
' +
                    '
Features
' +
                    '
Get Help
' +
                    '
Enterprise
' +
                '
' +
                '
Explore Data. Visualise. Act.
' +
            '' +
            '
' +
                '
' +
                    '
' +
                        '
Saiku
' +
                        '
Saiku has the power to change the way you think about your business and make decisions. Saiku provides powerful, web based analytics for everyone in your organisation. Quickly and easily analyse data from any data source to discover what is really happening inside and outside your organisation.
' +
                        '
Quick Links
' +
                        '
' +
                            '
Create a new query
' +
                            '
Create a dashboard
' +
                            '
 Visit the website
' +
                            '
Tutorials
' +
                        '
' +
                        '
Get Enterprise
' +
                    '
' +
                    '
' +
                        '
Discover more about Saiku
' +
                        '
Saiku Analytics provides both a Community Version and an Enterprise Version with added features. To find out more you can visit our website or watch the videos on our Youtube channel.
' +
                        '
If you are using Saiku Analytics in a business or commercial product, you can help give back in many ways. Swing by our IRC channel and help foster the community, join the mailing lists and ask/answer questions, sponsor a new feature, or best of all purchase an EE license, which funds development of Saiku Community Edition along with Enterprise Edition.
' +
                    '
' +
                '
' +
                '
' +
                    '
Saiku
' +
                    '
Features
' +
                    '
Web Based Analysis
' +
                    '
Saiku provides the user with an entirely browser based experience. We support all modern browsers, and our user interface is 100% HTML and Javascript.

Saiku uses REST based communications, this allows the development of custom user interfaces and facilitates the easy integration of the Saiku Server into other applications and services.
' +
                    '
Standards Compliant
' +
                    '
Saiku is based upon the Microsoft MDX query language and will work on most JDBC compliant data sources. We also provide a number of connectors to NOSQL data sources.
' +
                    '
Dynamic charting
' +
                    '
Saiku uses a flexible charting engine to provide a wide range of charts and graphs. These are all HTML & Javascript only and don\'t require flash to be installed on the computer.
' +
                    '
Pluggable visualisation engine
' +
                    '
Saiku Enterprise boasts a fully pluggable visualisation engine. This allows developers to build third party extensions and plug them into Saiku Enterprise to extend or replace the existing visualisations.
' +
                '
' +
                '
' +
                    '
Saiku
' +
                    '
Help
' +
                    '
We provide Training, Consulting and Support to ensure you get the most from Saiku and your data. Our services cover all aspects of data analysis including data strategy, design, architecture, deployment and application/software support.
' +
                    '
' +
                        '
' +
                            'Tutorials	' +
                            'Docs	' +
                            'Support	' +
                        '
' +
                        '
' +
                            'We have a number of click through tutorials to help get your started:' +
                                '
' +
                                    '
Beginners (Query building and charts)
' +
                                '
' +
                            '	' +
                            'Why not try  our new Documentation site
for community documentation.	' +
                            'If you require more,
contact us for support.	' +
                        '
' +
                    '
' +
                '
' +
                '
' +
                    '
Saiku
' +
                    '
Enterprise
' +
                    '
Saiku Enterprise is our fully supported and tested server and Pentaho plugin system. Buy Saiku Enterprise from as little as $15 per user per month and enjoy the addtional features Saiku Enterprise has to offer!
' +
                    '
To find out more visit our site or schedule a call with one of us and we can show you why you should choose Saiku Enterprise!
' +
                '
' +
            '
' +
        '
'
    ),

    initialize: function(args) {
        _.bindAll(this, 'caption');
        _.extend(this, Backbone.Events);
    },

    caption: function(increment) {
        return 'Home';
    },

    render: function() {
        this.$el.html(this.template());

        if (
            Settings.LICENSE &&
            Settings.LICENSE.licenseType !== undefined &&
            Settings.LICENSE.licenseType !== 'trial' &&
            Settings.LICENSE.licenseType !== 'Open Source License'
        ) {
            this.$el.find('.enterprisetoggle').css('visibility', 'hidden');
        }

        this.getContent();
        this.setupPage();

        $('#splash > nav > ul > li.active > a').click(function() {
            var active = $(this).attr('class');
            $('nav li').removeClass('active');
            $(this).parent().addClass('active');
            $('.stabs section').hide();
            $('#' + active).fadeIn();
        });

        return this;
    },

    click_head: function(event) {
        event.preventDefault();

        var target = event.target;
        var nav = $(target).attr('class').split(' ');
        var active = '';

        $('nav li').removeClass('active');
        $(target).parent().addClass('active');
        $('.stabs section').hide();

        if (nav.indexOf('welcome') > -1) {
            active = 'welcome';
        }
        else if (nav.indexOf('features') > -1) {
            active = 'features';
        }
        else if (nav.indexOf('help') > -1) {
            active = 'help';
        }
        else if (nav.indexOf('enterprise') > -1) {
            active = 'enterprise';
        }

        $('#' + active).fadeIn();
    },

    run_tour: function() {
        this.toolbar = Saiku.toolbar;

        var tour = new Tour({ toolbar: this.toolbar });

        tour.run_tour();
    },

    run_query: function() {
        Saiku.tabs.add(new Workspace());

        return false;
    },

    run_dashboard: function() {
        if (Saiku.Dashboards === undefined) {
            alert('Please upgrade to Saiku Enterprise for Dashboards');
        }
        else {
            var tab = _.find(Saiku.tabs._tabs, function(tab) {
                return tab.content instanceof Dashboards;
            });

            if (tab) {
                tab.select();
            }
            else {
                Saiku.tabs.add(new Dashboards());
            }

            return false;
        }

        return false;
    },

    setupPage: function() {
        var height = $(window).height();
        var active = $('nav li.active a').attr('class');

        $('body').height(height);
        $('.stabs section').each(function() {
            var vH = $(this).height();
            var dif = (height - vH) / 2 - 50;

            if (dif < 0) {
                dif = 20;
            }
        });

        $('#' + active).fadeIn();
    },

    getContent: function() {
        var self = this;

        $.ajax({
            type: 'GET',
            url: 'http://meteorite.bi/content.json',
            async: false,
            contentType: 'application/json',
            dataType: 'jsonp',
            jsonpCallback: 'jsonCallback2',
            cache: true,
            success: function(json) {
                // self.$el.find('#dyn_content').html(json.item[0].content);
                self.$el.find('.responsive-container').fitVids();
                self.$el.html(self.template());

                if (
                    Settings.LICENSE &&
                    Settings.LICENSE.licenseType !== 'trial' &&
                    Settings.LICENSE.licenseType !== 'Open Source License'
                ) {
                    self.$el.find('.enterprisetoggle').css('visibility', 'hidden');
                }
            },
            error: function(e) {
                self.$el.html(self.template());

                if (
                    Settings.LICENSE &&
                    Settings.LICENSE.licenseType !== 'trial' &&
                    Settings.LICENSE.licenseType !== 'Open Source License'
                ) {
                    self.$el.find('.enterprisetoggle').css('visibility', 'hidden');
                }
            }
        });
    }
});
<|endoftext|>