<commit_before>const fs = require('fs-extra');
const wmd = require('wmd');
const pug = require('pug');
const path = require('path');
var sass = require('node-sass');
var compressor = require('node-minify');

const { getDirectories, getFiles, getFile, getFolderContents } = require('./importHelpers');
const config = require('./../config.json');

const getListThemes = () => {
  const themePath = path.join(__dirname, './../theme/', config.theme);
  return new Promise((resolve,reject) => {
    getDirectories(themePath).then(folders => {
      resolve(folders);
    });
  });
}

const getThemeFolderItems = (pathString) => {
  const folderPath = pathString === '/' ?
    path.join(__dirname, './../theme/', config.theme) :
    path.join(__dirname, './../theme/', config.theme, pathString);
  return new Promise((resolve, reject) => {
    getFiles(folderPath).then(files => {
      const fullPathFiles = files.map(file => {
        return path.join(folderPath, file);
      });
      resolve(fullPathFiles);
    })
  });
}

const mapThemeFoldersToObject = (folders) => {
  let mapped = {};
  for (let folder in folders) {
    mapped[folders[folder]] = {};
  }
  return mapped;
}

const getThemeData = () => {
  let data = {};
  let promises = [];
  return new Promise((resolve, reject) => {
    getListThemes().then(directories => {
      data.lists = mapThemeFoldersToObject(directories);
      getThemeFolderItems('/').then(pages => {
        data.pages = pages;
        for (let folder in directories) {
          let promise = getThemeFolderItems(directories[folder]);
          promises.push(promise);
        }
        Promise.all(promises).then(results => {
          for (let folder in directories) {
            data.lists[directories[folder]] = results[folder];
          }
          resolve(data);
        });
      });
    });
  });
}

// retrieves theme file based on provided content markdown object
const getThemeFile = (contentObj) => {
  return new Promise((resolve, reject) => {
    if (contentObj.type === 'page') {
      getPageTheme(contentObj.slug).then(theme => {
        resolve(theme);
      });
    } else {
      getListItemTheme(contentObj.folder).then(theme => {
        resolve(theme);
      });
    }
  });
}

// get theme for page (based on page slug)
const getPageTheme = (pageName) => {
  return new Promise((resolve, reject) => {
    const themeUrl = path.join(__dirname, './../theme/', config.theme, `${pageName}.pug`);
    getFile(themeUrl).then(data => {
      resolve(data);
    });
  });
}

// get theme for list item (based on item's parent folder)
const getListItemTheme = (itemFolder) => {
  return new Promise((resolve, reject) => {
    const themeUrl = path.join(__dirname, './../theme/', config.theme, itemFolder, '/item.pug');
    getFile(themeUrl).then(data => {
      resolve(data);
    });
  });
}

// get theme for list (based on list name)
const getListTheme = (listName) => {
  return new Promise((resolve, reject) => {
    const themeUrl = path.join(__dirname, './../theme/', config.theme, listName, '/list.pug');
    getFile(themeUrl).then(data => {
      resolve(data);
    });
  });
}

// compile single sass file to output folder as css
const compileSassFile = (url) => {
  const outputUrl = path.join(__dirname, './../output/static/css');
  const srcFolder = path.parse(url).dir;
  const fileName = path.parse(url).name;
  const outputFileUrl = path.join(outputUrl, `${fileName}.css`);
  return new Promise((resolve, reject) => {
    sass.render({
      file: url,
      outFile: outputFileUrl,
      sourceMap: true,
      outputStyle: 'compressed',
      includePaths: [srcFolder],
    }, function(err, result) {
      if (err) {
        console.warn('Error during sass compilation! ', err);
        reject();
      } else {
        fs.outputFile(outputFileUrl, result.css, function(fileErr){
          if(!fileErr){
            resolve();
          } else {
            console.warn('Error during css file save! ', fileErr);
            reject();
          }
        });
      }
    });
  });
}

// compile sass styles to css
const compileStyles = () => {
  const urlToSass = path.join(__dirname, './../theme/', config.theme, '/static/scss');
  return new Promise((resolve, reject) => {
    getFolderContents(urlToSass).then((files) => {
      let promises = [];
      for (let file of files) {
        const pathToFile = path.join(urlToSass, file);
        promises.push(compileSassFile(pathToFile));
      }
      Promise.all(promises).then(() => {
        console.log('All styles compiled!');
        resolve();
      })
    });
  });
};

// uglify theme js files
const uglifyScripts = () => {
  const themeScriptsPath = path.join(__dirname, './../theme/', config.theme, 'static/js');
  const outputScriptsPath = path.join(__dirname, './../output/static/js/bundle.js');
  return new Promise((resolve, reject) => {
    let promise = compressor.minify({
      compressor: 'uglifyjs',
      input: `${themeScriptsPath}/*.js`,
      output: outputScriptsPath,
    });

    return promise.then(() => {
      console.log('All theme scripts uglified!');
      resolve();
    });
  });
};

// copy theme static assets to output
const copyThemeAssets = () => {
  const themeAssetsUrl = path.join(__dirname, './../theme', config.theme, 'static/assets');
  const outputAssetsUrl = path.join(__dirname, './../output/static/assets');
  return new Promise((resolve, reject) => {
    fs.copy(themeAssetsUrl, outputAssetsUrl, function (err) {
      if (err) {
        console.error('There was an error when compiling static theme assets! ', err);
        reject();
      } else {
        console.log("Theme assets compiled!");
        resolve();
      }
    });
  });
}

module.exports.getListThemes = getListThemes;
module.exports.getThemeFolderItems = getThemeFolderItems;
module.exports.getThemeData = getThemeData;
module.exports.getThemeFile = getThemeFile;
module.exports.getPageTheme = getPageTheme;
module.exports.getListItemTheme = getListItemTheme;
module.exports.getListTheme = getListTheme;
module.exports.compileStyles = compileStyles;
module.exports.uglifyScripts = uglifyScripts;
module.exports.copyThemeAssets = copyThemeAssets;
<commit_msg>Updated js compiler.<commit_after>const fs = require('fs-extra');
const wmd = require('wmd');
const pug = require('pug');
const path = require('path');
var sass = require('node-sass');
var compressor = require('node-minify');

const { getDirectories, getFiles, getFile, getFolderContents } = require('./importHelpers');
const config = require('./../config.json');

const getListThemes = () => {
  const themePath = path.join(__dirname, './../theme/', config.theme);
  return new Promise((resolve,reject) => {
    getDirectories(themePath).then(folders => {
      resolve(folders);
    });
  });
}

const getThemeFolderItems = (pathString) => {
  const folderPath = pathString === '/' ?
    path.join(__dirname, './../theme/', config.theme) :
    path.join(__dirname, './../theme/', config.theme, pathString);
  return new Promise((resolve, reject) => {
    getFiles(folderPath).then(files => {
      const fullPathFiles = files.map(file => {
        return path.join(folderPath, file);
      });
      resolve(fullPathFiles);
    })
  });
}

const mapThemeFoldersToObject = (folders) => {
  let mapped = {};
  for (let folder in folders) {
    mapped[folders[folder]] = {};
  }
  return mapped;
}

const getThemeData = () => {
  let data = {};
  let promises = [];
  return new Promise((resolve, reject) => {
    getListThemes().then(directories => {
      data.lists = mapThemeFoldersToObject(directories);
      getThemeFolderItems('/').then(pages => {
        data.pages = pages;
        for (let folder in directories) {
          let promise = getThemeFolderItems(directories[folder]);
          promises.push(promise);
        }
        Promise.all(promises).then(results => {
          for (let folder in directories) {
            data.lists[directories[folder]] = results[folder];
          }
          resolve(data);
        });
      });
    });
  });
}

// retrieves theme file based on provided content markdown object
const getThemeFile = (contentObj) => {
  return new Promise((resolve, reject) => {
    if (contentObj.type === 'page') {
      getPageTheme(contentObj.slug).then(theme => {
        resolve(theme);
      });
    } else {
      getListItemTheme(contentObj.folder).then(theme => {
        resolve(theme);
      });
    }
  });
}

// get theme for page (based on page slug)
const getPageTheme = (pageName) => {
  return new Promise((resolve, reject) => {
    const themeUrl = path.join(__dirname, './../theme/', config.theme, `${pageName}.pug`);
    getFile(themeUrl).then(data => {
      resolve(data);
    });
  });
}

// get theme for list item (based on item's parent folder)
const getListItemTheme = (itemFolder) => {
  return new Promise((resolve, reject) => {
    const themeUrl = path.join(__dirname, './../theme/', config.theme, itemFolder, '/item.pug');
    getFile(themeUrl).then(data => {
      resolve(data);
    });
  });
}

// get theme for list (based on list name)
const getListTheme = (listName) => {
  return new Promise((resolve, reject) => {
    const themeUrl = path.join(__dirname, './../theme/', config.theme, listName, '/list.pug');
    getFile(themeUrl).then(data => {
      resolve(data);
    });
  });
}

// compile single sass file to output folder as css
const compileSassFile = (url) => {
  const outputUrl = path.join(__dirname, './../output/static/css');
  const srcFolder = path.parse(url).dir;
  const fileName = path.parse(url).name;
  const outputFileUrl = path.join(outputUrl, `${fileName}.css`);
  return new Promise((resolve, reject) => {
    sass.render({
      file: url,
      outFile: outputFileUrl,
      sourceMap: true,
      outputStyle: 'compressed',
      includePaths: [srcFolder],
    }, function(err, result) {
      if (err) {
        console.warn('Error during sass compilation! ', err);
        reject();
      } else {
        fs.outputFile(outputFileUrl, result.css, function(fileErr){
          if(!fileErr){
            resolve();
          } else {
            console.warn('Error during css file save! ', fileErr);
            reject();
          }
        });
      }
    });
  });
}

// compile sass styles to css
const compileStyles = () => {
  const urlToSass = path.join(__dirname, './../theme/', config.theme, '/static/scss');
  return new Promise((resolve, reject) => {
    getFolderContents(urlToSass).then((files) => {
      let promises = [];
      for (let file of files) {
        const pathToFile = path.join(urlToSass, file);
        promises.push(compileSassFile(pathToFile));
      }
      Promise.all(promises).then(() => {
        console.log('All styles compiled!');
        resolve();
      })
    });
  });
};

// uglify theme js files
const uglifyScripts = () => {
  const themeScriptsPath = path.join(__dirname, './../theme/', config.theme, 'static/js');
  const outputScriptsPath = path.join(__dirname, './../output/static/js/bundle.js');
  return new Promise((resolve, reject) => {
    let promise = compressor.minify({
      compressor: 'gcc',
      input: `${themeScriptsPath}/*.js`,
      output: outputScriptsPath,
      options: {
        warnings: true,
      },
    });
    return promise.then(() => {
      console.log('All theme scripts uglified!');
      resolve();
    });
  });
};

// copy theme static assets to output
const copyThemeAssets = () => {
  const themeAssetsUrl = path.join(__dirname, './../theme', config.theme, 'static/assets');
  const outputAssetsUrl = path.join(__dirname, './../output/static/assets');
  return new Promise((resolve, reject) => {
    fs.copy(themeAssetsUrl, outputAssetsUrl, function (err) {
      if (err) {
        console.error('There was an error when compiling static theme assets! ', err);
        reject();
      } else {
        console.log("Theme assets compiled!");
        resolve();
      }
    });
  });
}

module.exports.getListThemes = getListThemes;
module.exports.getThemeFolderItems = getThemeFolderItems;
module.exports.getThemeData = getThemeData;
module.exports.getThemeFile = getThemeFile;
module.exports.getPageTheme = getPageTheme;
module.exports.getListItemTheme = getListItemTheme;
module.exports.getListTheme = getListTheme;
module.exports.compileStyles = compileStyles;
module.exports.uglifyScripts = uglifyScripts;
module.exports.copyThemeAssets = copyThemeAssets;
<|endoftext|>


<commit_before>'use strict';
const models = require('../models');
const $=module.exports={};

$.check=function *(){
  const users = yield models.User.find(this.query).lean().exec();
  this.assert(users.length>0,'no users found',404);
  this.status=200;
};

$.create=function *(){
  const user = yield models.User.create(this.request.body);
  this.body=user;
};

$.show=function *(){
  const user = yield models.User.findById(this.params.user).lean().exec();
  this.assert(user,'user not found',404);
  this.body=user;
};

$.update=function *(){
  const user = yield models.User.findById(this.params.user).exec();
  this.assert(user,'user not found',404);
  user=yield user.patch(this.request.body);
  this.status=200;
};

$.destroy=function *(){
  const user = yield models.User.findByIdAndRemove(this.params.user).exec();
  this.assert(user,'user not found',404);
  this.status=200;
};
<commit_msg>Fix user patch method in api<commit_after>'use strict';
const models = require('../models');
const jsonpatch = require('fast-json-patch');
const $=module.exports={};

$.check=function *(){
  const users = yield models.User.find(this.query).lean().exec();
  this.assert(users.length>0,'no users found',404);
  this.status=200;
};

$.create=function *(){
  const user = yield models.User.create(this.request.body);
  this.body=user;
};

$.show=function *(){
  const user = yield models.User.findById(this.params.user).lean().exec();
  this.assert(user,'user not found',404);
  this.body=user;
};

$.update=function *(){
  const user = yield models.User.findById(this.params.user).exec();
  this.assert(user,'user not found',404);
  const patch = jsonpatch.apply(user,this.request.body);
  if(patch===true){
    yield user.save();
    this.status=200;
  }
  else{
    this.throw('patch not successful');
  }
};

$.destroy=function *(){
  const user = yield models.User.findByIdAndRemove(this.params.user).exec();
  this.assert(user,'user not found',404);
  this.status=200;
};
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { Text, View, Alert, TextInput, Linking, Image, ActivityIndicator } from 'react-native';
import SubmitButton from 'react-native-submit-button';
import Toast from 'react-native-simple-toast';
import { TextButton, RaisedTextButton } from 'react-native-material-buttons';
import { Button, Icon } from 'react-native-elements';
import firebase from 'firebase';
import ImagePicker from 'react-native-image-picker';
import RNFetchBlob from 'react-native-fetch-blob'

class NewBG extends Component {

    constructor(props) {
        super(props);
        this.state = { bgVal: '', carbsAm: '', insUn: '', desc: '', imgsrc: '', actloading: false, dp: null };

    }

    SaveBG() {
        const BG = { bgVal, carbsAm, insUn, desc } = this.state;
        const { currentUser } = firebase.auth();
        firebase.database().ref(`/users/${currentUser.uid}/Bglst`)
            .push({ BG }).then(this.onSaveSuccess.bind(this));
    }

    onSaveSuccess() {
        Toast.show('Bg Saved Successfully!', Toast.SHORT);
        this.setState({ bgVal: '', carbsAm: '', insUn: '', desc: '', imgsrc: '' });
    }

    HelpCarbs() {
        Linking.openURL('http://www.foodsdictionary.co.il')
    }

    TakePic() {
        var options = {
            title: 'Select Avatar',
            customButtons: [
                { name: 'fb', title: 'Choose Photo from Facebook' },
            ],
            storageOptions: {
                skipBackup: true,
                path: 'images'
            }
        };

        this.setState({ actloading: true });
        const { currentUser } = firebase.auth();
        const Blob = RNFetchBlob.polyfill.Blob;
        const fs = RNFetchBlob.fs;
        window.XMLHttpRequest = RNFetchBlob.polyfill.XMLHttpRequest;
        window.Blob = Blob;

        ImagePicker.showImagePicker(options, (image) => {
            const imagePath = image.path
            console.log(image.path);
            let uploadBlob = null

            const imageRef = firebase.storage().ref(currentUser.uid).child("Bg.jpg") //check here what to do with the name
            let mime = 'image/jpg'
            fs.readFile(imagePath, 'base64')
                .then((data) => {
                    //console.log(data);
                    return Blob.build(data, { type: `${mime};BASE64` })
                })
                .then((blob) => {
                    uploadBlob = blob
                    return imageRef.put(blob, { contentType: mime })
                })
                .then((url) => {

                    console.log('url :' + url);

                    this.setState({ imgsrc: url.downloadURL });
                    console.log('imgsrc:');
                    console.log(this.state.imgsrc);

                });

        });

    }

    render() {
        const { textStyle, viewStyle, buttonStyle } = styles;
        return (

            <View style={{ justifyContent: 'flex-start' }}>
                <TextInput
                    keyboardType={'numeric'}
                    style={{ borderColor: 'red', width: 100, paddingLeft: 10, fontSize: 20 }}
                    onChangeText={(bgVal) => this.setState({ bgVal })}
                    value={this.state.bgVal}
                    maxLength={3}
                    placeholder={'Enter BG'}
                />
                <View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
                    <TextInput
                        keyboardType={'numeric'}
                        maxLength={3}
                        style={{ paddingLeft: 10, fontSize: 20, width: 250 }}
                        onChangeText={(carbsAm) => this.setState({ carbsAm })}
                        value={this.state.carbsAm}
                        placeholder={'Enter Carbs Amount'}
                    />
                    <Icon
                        style={{ paddingRight: 5, paddingTop: 12 }}
                        name='help'
                        color='grey'
                        size={30}
                        onPress={this.HelpCarbs.bind(this)}
                    />
                    <Icon
                        style={{ paddingRight: 80, paddingTop: 12 }}
                        name='camera-alt'
                        color='#00d311'
                        size={30}
                        onPress={this.TakePic.bind(this)}
                    />

                </View>

                <TextInput
                    keyboardType={'numeric'}
                    style={{ paddingLeft: 10, fontSize: 20 }}
                    onChangeText={(insUn) => this.setState({ insUn })}
                    value={this.state.insUn}
                    maxLength={5}
                    placeholder={'Enter Insulin Uinits Amount'}
                />

                <TextInput
                    multiline={true}
                    style={{ borderColor: 'red', width: 300, paddingLeft: 10, fontSize: 20 }}
                    onChangeText={(desc) => this.setState({ desc })}
                    value={this.state.desc}
                    placeholder={'Enter Meal Description'}
                />

                <View style={{ borderRadius: 10, marginTop: 20 }}>
                    {/* <SubmitButton /> */}
                    <Button
                        icon={{ name: 'opacity', size: 32, color: 'red' }}
                        buttonStyle={{ backgroundColor: '#2bce81', borderRadius: 40 }}
                        textStyle={{ textAlign: 'center', fontSize: 25 }}
                        title={`Save BG    `}
                        onPress={this.SaveBG.bind(this)}
                    />
                </View>

                <Image source={this.state.imgsrc}>
                </Image>

            </View >

        );
    }

}

export default NewBG;

const styles = {

    viewStyle:
    {
        backgroundColor: '#ccffd1',
        justifyContent: 'center',
        alignItems: 'center',
        height: 70,
        elevation: 5,
        position: 'relative'
    },
    textStyle:
    {
        fontSize: 40
    },

    buttonStyle:
    {

        alignItems: 'left',
    },

};
<commit_msg>Upload photo works with showing and design<commit_after>import React, { Component } from 'react';
import { Text, View, Alert, TextInput, Linking, Image, ActivityIndicator } from 'react-native';
import SubmitButton from 'react-native-submit-button';
import Toast from 'react-native-simple-toast';
import { TextButton, RaisedTextButton } from 'react-native-material-buttons';
import { Button, Icon } from 'react-native-elements';
import firebase from 'firebase';
import ImagePicker from 'react-native-image-picker';
import RNFetchBlob from 'react-native-fetch-blob'

class NewBG extends Component {

    constructor(props) {
        super(props);
        this.state = { bgVal: '', carbsAm: '', insUn: '', desc: '', imgsrc: '', actloading: null };

    }

    SaveBG() {
        const BG = { bgVal, carbsAm, insUn, desc } = this.state;
        const { currentUser } = firebase.auth();
        firebase.database().ref(`/users/${currentUser.uid}/Bglst`)
            .push({ BG }).then(this.onSaveSuccess.bind(this));
    }

    onSaveSuccess() {
        Toast.show('Bg Saved Successfully!', Toast.SHORT);
        this.setState({ bgVal: '', carbsAm: '', insUn: '', desc: '', imgsrc: '' });
    }

    HelpCarbs() {
        Linking.openURL('http://www.foodsdictionary.co.il')
    }

    TakePic() {
        const { currentUser } = firebase.auth();
        const Blob = RNFetchBlob.polyfill.Blob;
        const fs = RNFetchBlob.fs;
        window.XMLHttpRequest = RNFetchBlob.polyfill.XMLHttpRequest;
        window.Blob = Blob;

        ImagePicker.showImagePicker((image) => {
            const imagePath = image.path
            console.log(image.path);
            let uploadBlob = null
            if (imagePath)
                this.setState({ actloading: true });
            else
                this.setState({ actloading: false });

            const imageRef = firebase.storage().ref(currentUser.uid).child("Bg.jpg") //check here what to do with the name
            let mime = 'image/jpg'
            fs.readFile(imagePath, 'base64')
                .then((data) => {
                    //console.log(data);
                    return Blob.build(data, { type: `${mime};BASE64` })
                })
                .then((blob) => {
                    uploadBlob = blob
                    return imageRef.put(blob, { contentType: mime })
                })
                .then((url) => {

                    console.log('url :' + url);

                    this.setState({ imgsrc: url.downloadURL });
                    console.log('imgsrc:');
                    console.log(this.state.imgsrc);
                    this.setState({ actloading: false });
                });

        });

    }

    ShowImage(self) {
        if (!(self.state.actloading)) {
            return (
                <View style={{ paddingRight: 0, paddingTop: 2 }}>
                    <Image
                        style={{ width: 40, height: 40, marginRight: 6, marginBottom: 4, marginTop: 2.5, marginLeft: 2, borderRadius: 100 }}
                        source={{ uri: self.state.imgsrc }}>
                    </Image>
                </View>
            );
        }
        else {
            return (
                <View style={{ paddingRight: 10, paddingTop: 16 }}>
                    <ActivityIndicator animating={self.state.loading} />
                </View>
            );

        }
    }

    render() {
        const { textStyle, viewStyle, buttonStyle } = styles;
        return (

            <View style={{ justifyContent: 'flex-start' }}>
                <TextInput
                    keyboardType={'numeric'}
                    style={{ borderColor: 'red', width: 100, paddingLeft: 10, fontSize: 20 }}
                    onChangeText={(bgVal) => this.setState({ bgVal })}
                    value={this.state.bgVal}
                    maxLength={3}
                    placeholder={'Enter BG'}
                />
                {/* CarbsSection image link and take photo */}
                <View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
                    <TextInput
                        keyboardType={'numeric'}
                        maxLength={3}
                        style={{ paddingLeft: 10, fontSize: 20, width: 250 }}
                        onChangeText={(carbsAm) => this.setState({ carbsAm })}
                        value={this.state.carbsAm}
                        placeholder={'Enter Carbs Amount'}
                    />
                    {/*  btn Help Carbs link */}
                    <Icon
                        style={{ paddingRight: 1, paddingTop: 12 }}
                        name='help'
                        color='grey'
                        size={30}
                        onPress={this.HelpCarbs.bind(this)}
                    />
                    {/* TakePicture btn */}
                    <Icon
                        style={{ paddingRight: 1, paddingTop: 12 }}
                        name='camera-alt'
                        color={this.state.imgsrc ? '#00d311' : 'grey'}
                        size={30}
                        onPress={this.TakePic.bind(this)}
                    />
                    {/* Image That Uploaded */}

                    {this.ShowImage(this)}

                </View>

                <TextInput
                    keyboardType={'numeric'}
                    style={{ paddingLeft: 10, fontSize: 20 }}
                    onChangeText={(insUn) => this.setState({ insUn })}
                    value={this.state.insUn}
                    maxLength={5}
                    placeholder={'Enter Insulin Uinits Amount'}
                />

                <TextInput
                    multiline={true}
                    style={{ borderColor: 'red', width: 300, paddingLeft: 10, fontSize: 20 }}
                    onChangeText={(desc) => this.setState({ desc })}
                    value={this.state.desc}
                    placeholder={'Enter Meal Description'}
                />

                <View style={{ borderRadius: 10, marginTop: 20 }}>
                    {/* <SubmitButton /> */}
                    <Button
                        icon={{ name: 'opacity', size: 32, color: 'red' }}
                        buttonStyle={{ backgroundColor: '#2bce81', borderRadius: 40 }}
                        textStyle={{ textAlign: 'center', fontSize: 25 }}
                        title={`Save BG    `}
                        onPress={this.SaveBG.bind(this)}
                    />
                </View>

            </View >

        );
    }

}

export default NewBG;

const styles = {

    viewStyle:
    {
        backgroundColor: '#ccffd1',
        justifyContent: 'center',
        alignItems: 'center',
        height: 70,
        elevation: 5,
        position: 'relative'
    },
    textStyle:
    {
        fontSize: 40
    },

    buttonStyle:
    {

        alignItems: 'left',
    },

};
<|endoftext|>


<commit_before>import {Pos} from "../model"
import {ProseMirrorError} from "../util/error"
import {contains, browser} from "../dom"

import {posFromDOM, pathToDOM, DOMFromPos, coordsAtPos} from "./dompos"

// ;; Error type used to signal selection-related problems.
export class SelectionError extends ProseMirrorError {}

export class SelectionState {
  constructor(pm, range) {
    this.pm = pm
    this.range = range

    this.lastNonNodePos = null

    this.polling = null
    this.lastAnchorNode = this.lastHeadNode = this.lastAnchorOffset = this.lastHeadOffset = null
    this.lastNode = null

    pm.content.addEventListener("focus", () => this.receivedFocus())
    this.poller = this.poller.bind(this)
  }

  setAndSignal(range, clearLast) {
    this.set(range, clearLast)
    // :: () #path=ProseMirror#events#selectionChange
    // Indicates that the editor's selection has changed.
    this.pm.signal("selectionChange")
  }

  set(range, clearLast) {
    this.pm.ensureOperation({readSelection: false})
    this.range = range
    if (!range.node) this.lastNonNodePos = null
    if (clearLast !== false) this.lastAnchorNode = null
  }

  poller() {
    if (hasFocus(this.pm)) {
      if (!this.pm.operation) this.readFromDOM()
      this.polling = setTimeout(this.poller, 100)
    } else {
      this.polling = null
    }
  }

  startPolling() {
    clearTimeout(this.polling)
    this.polling = setTimeout(this.poller, 50)
  }

  fastPoll() {
    this.startPolling()
  }

  stopPolling() {
    clearTimeout(this.polling)
    this.polling = null
  }

  domChanged() {
    let sel = window.getSelection()
    return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset ||
      sel.focusNode != this.lastHeadNode || sel.focusOffset != this.lastHeadOffset
  }

  storeDOMState() {
    let sel = window.getSelection()
    this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset
    this.lastHeadNode = sel.focusNode; this.lastHeadOffset = sel.focusOffset
  }

  readFromDOM() {
    if (this.pm.input.composing || !hasFocus(this.pm) || !this.domChanged()) return false

    let sel = window.getSelection(), doc = this.pm.doc
    let anchor = posFromDOM(this.pm, sel.anchorNode, sel.anchorOffset)
    let head = sel.isCollapsed ? anchor : posFromDOM(this.pm, sel.focusNode, sel.focusOffset)

    let newRange = findSelectionNear(doc, head, this.range.head && this.range.head.cmp(head) < 0 ? -1 : 1)
    if (newRange instanceof TextSelection && doc.path(anchor.path).isTextblock)
      newRange = new TextSelection(anchor, newRange.head)
    this.setAndSignal(newRange)

    if (newRange instanceof NodeSelection || newRange.head.cmp(head) || newRange.anchor.cmp(anchor)) {
      this.toDOM()
    } else {
      this.clearNode()
      this.storeDOMState()
    }
    return true
  }

  toDOM(takeFocus) {
    if (!hasFocus(this.pm)) {
      if (!takeFocus) return
      // See https://bugzilla.mozilla.org/show_bug.cgi?id=921444
      else if (browser.gecko) this.pm.content.focus()
    }
    if (this.range instanceof NodeSelection)
      this.nodeToDOM()
    else
      this.rangeToDOM()
  }

  nodeToDOM() {
    let dom = pathToDOM(this.pm.content, this.range.from.toPath())
    if (dom != this.lastNode) {
      this.clearNode()
      dom.classList.add("ProseMirror-selectednode")
      this.pm.content.classList.add("ProseMirror-nodeselection")
      this.lastNode = dom
    }
    let range = document.createRange(), sel = window.getSelection()
    range.selectNode(dom)
    sel.removeAllRanges()
    sel.addRange(range)
    this.storeDOMState()
  }

  rangeToDOM() {
    this.clearNode()

    let anchor = DOMFromPos(this.pm.content, this.range.anchor)
    let head = DOMFromPos(this.pm.content, this.range.head)

    let sel = window.getSelection(), range = document.createRange()
    if (sel.extend) {
      range.setEnd(anchor.node, anchor.offset)
      range.collapse(false)
    } else {
      if (this.range.anchor.cmp(this.range.head) > 0) { let tmp = anchor; anchor = head; head = tmp }
      range.setEnd(head.node, head.offset)
      range.setStart(anchor.node, anchor.offset)
    }
    sel.removeAllRanges()
    sel.addRange(range)
    if (sel.extend)
      sel.extend(head.node, head.offset)
    this.storeDOMState()
  }

  clearNode() {
    if (this.lastNode) {
      this.lastNode.classList.remove("ProseMirror-selectednode")
      this.pm.content.classList.remove("ProseMirror-nodeselection")
      this.lastNode = null
      return true
    }
  }

  receivedFocus() {
    if (this.polling == null) this.startPolling()
  }
}

// ;; An editor selection. Can be one of two selection types:
// `TextSelection` and `NodeSelection`. Both have the properties
// listed here, but also contain more information (such as the
// selected [node](#NodeSelection.node) or the
// [head](#TextSelection.head) and [anchor](#TextSelection.anchor)).
export class Selection {
  // :: Pos #path=Selection.prototype.from
  // The start of the selection.

  // :: Pos #path=Selection.prototype.to
  // The end of the selection.

  // :: bool #path=Selection.empty
  // True if the selection is an empty text selection (head an anchor
  // are the same).

  // :: (other: Selection) → bool #path=Selection.eq
  // Test whether the selection is the same as another selection.

  // :: (doc: Node, mapping: Mappable) → Selection #path=Selection.map
  // Map this selection through a [mappable](#Mappable) thing. `doc`
  // should be the new document, to which we are mapping.
}

// ;; A text selection represents a classical editor
// selection, with a head (the moving side) and anchor (immobile
// side), both of which point into textblock nodes. It can be empty (a
// regular cursor position).
export class TextSelection extends Selection {
  // :: (Pos, ?Pos)
  // Construct a text selection. When `head` is not given, it defaults
  // to `anchor`.
  constructor(anchor, head) {
    super()
    // :: Pos
    // The selection's immobile side (does not move when pressing
    // shift-arrow).
    this.anchor = anchor
    // :: Pos
    // The selection's mobile side (the side that moves when pressing
    // shift-arrow).
    this.head = head || anchor
  }

  get inverted() { return this.anchor.cmp(this.head) > 0 }
  get from() { return this.inverted ? this.head : this.anchor }
  get to() { return this.inverted ? this.anchor : this.head }
  get empty() { return this.anchor.cmp(this.head) == 0 }

  eq(other) {
    return other instanceof TextSelection && !other.head.cmp(this.head) && !other.anchor.cmp(this.anchor)
  }

  map(doc, mapping) {
    let head = mapping.map(this.head).pos
    if (!doc.path(head.path).isTextblock)
      return findSelectionNear(doc, head)
    let anchor = mapping.map(this.anchor).pos
    return new TextSelection(doc.path(anchor.path).isTextblock ? anchor : head, head)
  }
}

// ;; A node selection is a selection that points at a
// single node. All nodes marked [selectable](#NodeType.selectable)
// can be the target of a node selection. In such an object, `from`
// and `to` point directly before and after the selected node.
export class NodeSelection extends Selection {
  // :: (Pos, Pos, Node)
  // Create a node selection. Does not verify the validity of its
  // arguments. Use `ProseMirror.setNodeSelection` for an easier,
  // error-checking way to create a node selection.
  constructor(from, to, node) {
    super()
    this.from = from
    this.to = to
    // :: Node The selected node.
    this.node = node
  }

  get empty() { return false }

  eq(other) {
    return other instanceof NodeSelection && !this.from.cmp(other.from)
  }

  map(doc, mapping) {
    let from = mapping.map(this.from, 1).pos
    let to = mapping.map(this.to, -1).pos
    if (Pos.samePath(from.path, to.path) && from.offset == to.offset - 1) {
      let node = doc.nodeAfter(from)
      if (node.type.selectable) return new NodeSelection(from, to, node)
    }
    return findSelectionNear(doc, from)
  }
}

export function rangeFromDOMLoose(pm) {
  if (!hasFocus(pm)) return null
  let sel = window.getSelection()
  return new TextSelection(posFromDOM(pm, sel.anchorNode, sel.anchorOffset, true),
                           posFromDOM(pm, sel.focusNode, sel.focusOffset, true))
}

export function hasFocus(pm) {
  let sel = window.getSelection()
  return sel.rangeCount && contains(pm.content, sel.anchorNode)
}

function findSelectionIn(doc, path, offset, dir, text) {
  let node = doc.path(path)
  if (node.isTextblock) return new TextSelection(new Pos(path, offset))

  for (let i = offset + (dir > 0 ? 0 : -1); dir > 0 ? i < node.size : i >= 0; i += dir) {
    let child = node.child(i)
    if (!text && child.type.contains == null && child.type.selectable)
      return new NodeSelection(new Pos(path, i), new Pos(path, i + 1), child)
    path.push(i)
    let inside = findSelectionIn(doc, path, dir < 0 ? child.size : 0, dir, text)
    if (inside) return inside
    path.pop()
  }
}

// FIXME we'll need some awareness of bidi motion when determining block start and end

export function findSelectionFrom(doc, pos, dir, text) {
  for (let path = pos.path.slice(), offset = pos.offset;;) {
    let found = findSelectionIn(doc, path, offset, dir, text)
    if (found) return found
    if (!path.length) break
    offset = path.pop() + (dir > 0 ? 1 : 0)
  }
}

export function findSelectionNear(doc, pos, bias = 1, text) {
  let result = findSelectionFrom(doc, pos, bias, text) || findSelectionFrom(doc, pos, -bias, text)
  if (!result) SelectionError("Searching for selection in invalid document " + doc)
  return result
}

export function findSelectionAtStart(node, path = [], text) {
  return findSelectionIn(node, path.slice(), 0, 1, text)
}

export function findSelectionAtEnd(node, path = [], text) {
  return findSelectionIn(node, path.slice(), node.size, -1, text)
}

export function verticalMotionLeavesTextblock(pm, pos, dir) {
  let dom = pathToDOM(pm.content, pos.path)
  let coords = coordsAtPos(pm, pos)
  for (let child = dom.firstChild; child; child = child.nextSibling) {
    if (child.nodeType != 1) continue
    let boxes = child.getClientRects()
    for (let i = 0; i < boxes.length; i++) {
      let box = boxes[i]
      if (dir < 0 ? box.bottom < coords.top : box.top > coords.bottom)
        return false
    }
  }
  return true
}
<commit_msg>Add docs for SelectionState<commit_after>import {Pos} from "../model"
import {ProseMirrorError} from "../util/error"
import {contains, browser} from "../dom"

import {posFromDOM, pathToDOM, DOMFromPos, coordsAtPos} from "./dompos"

// ;; Error type used to signal selection-related problems.
export class SelectionError extends ProseMirrorError {}

// Track the state of the current editor selection. Keeps the editor
// selection in sync with the DOM selection by polling for changes,
// as there is no DOM event for DOM selection changes.
export class SelectionState {
  constructor(pm, range) {
    this.pm = pm
    // The current editor selection.
    this.range = range

    this.lastNonNodePos = null

    // The timeout ID for the poller when active.
    this.polling = null
    // Track the state of the DOM selection.
    this.lastAnchorNode = this.lastHeadNode = this.lastAnchorOffset = this.lastHeadOffset = null
    // The corresponding DOM node when a node selection is active.
    this.lastNode = null

    pm.content.addEventListener("focus", () => this.receivedFocus())

    this.poller = this.poller.bind(this)
  }

  // : (Selection, boolean)
  // Set the current selection and signal an event on the editor.
  setAndSignal(range, clearLast) {
    this.set(range, clearLast)
    // :: () #path=ProseMirror#events#selectionChange
    // Indicates that the editor's selection has changed.
    this.pm.signal("selectionChange")
  }

  // : (Selection, boolean)
  // Set the current selection.
  set(range, clearLast) {
    this.pm.ensureOperation({readSelection: false})
    this.range = range
    if (!range.node) this.lastNonNodePos = null
    if (clearLast !== false) this.lastAnchorNode = null
  }

  poller() {
    if (hasFocus(this.pm)) {
      if (!this.pm.operation) this.readFromDOM()
      this.polling = setTimeout(this.poller, 100)
    } else {
      this.polling = null
    }
  }

  startPolling() {
    clearTimeout(this.polling)
    this.polling = setTimeout(this.poller, 50)
  }

  fastPoll() {
    this.startPolling()
  }

  stopPolling() {
    clearTimeout(this.polling)
    this.polling = null
  }

  // : () → bool
  // Whether the DOM selection has changed from the last known state.
  domChanged() {
    let sel = window.getSelection()
    return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset ||
      sel.focusNode != this.lastHeadNode || sel.focusOffset != this.lastHeadOffset
  }

  // Store the current state of the DOM selection.
  storeDOMState() {
    let sel = window.getSelection()
    this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset
    this.lastHeadNode = sel.focusNode; this.lastHeadOffset = sel.focusOffset
  }

  // : () → bool
  // When the DOM selection changes in a notable manner, modify the
  // current selection state to match.
  readFromDOM() {
    if (this.pm.input.composing || !hasFocus(this.pm) || !this.domChanged()) return false

    let sel = window.getSelection(), doc = this.pm.doc
    let anchor = posFromDOM(this.pm, sel.anchorNode, sel.anchorOffset)
    let head = sel.isCollapsed ? anchor : posFromDOM(this.pm, sel.focusNode, sel.focusOffset)

    let newRange = findSelectionNear(doc, head, this.range.head && this.range.head.cmp(head) < 0 ? -1 : 1)
    if (newRange instanceof TextSelection && doc.path(anchor.path).isTextblock)
      newRange = new TextSelection(anchor, newRange.head)
    this.setAndSignal(newRange)

    if (newRange instanceof NodeSelection || newRange.head.cmp(head) || newRange.anchor.cmp(anchor)) {
      this.toDOM()
    } else {
      this.clearNode()
      this.storeDOMState()
    }
    return true
  }

  toDOM(takeFocus) {
    if (!hasFocus(this.pm)) {
      if (!takeFocus) return
      // See https://bugzilla.mozilla.org/show_bug.cgi?id=921444
      else if (browser.gecko) this.pm.content.focus()
    }
    if (this.range instanceof NodeSelection)
      this.nodeToDOM()
    else
      this.rangeToDOM()
  }

  // Make changes to the DOM for a node selection.
  nodeToDOM() {
    let dom = pathToDOM(this.pm.content, this.range.from.toPath())
    if (dom != this.lastNode) {
      this.clearNode()
      dom.classList.add("ProseMirror-selectednode")
      this.pm.content.classList.add("ProseMirror-nodeselection")
      this.lastNode = dom
    }
    let range = document.createRange(), sel = window.getSelection()
    range.selectNode(dom)
    sel.removeAllRanges()
    sel.addRange(range)
    this.storeDOMState()
  }

  // Make changes to the DOM for a text selection.
  rangeToDOM() {
    this.clearNode()

    let anchor = DOMFromPos(this.pm.content, this.range.anchor)
    let head = DOMFromPos(this.pm.content, this.range.head)

    let sel = window.getSelection(), range = document.createRange()
    if (sel.extend) {
      range.setEnd(anchor.node, anchor.offset)
      range.collapse(false)
    } else {
      if (this.range.anchor.cmp(this.range.head) > 0) { let tmp = anchor; anchor = head; head = tmp }
      range.setEnd(head.node, head.offset)
      range.setStart(anchor.node, anchor.offset)
    }
    sel.removeAllRanges()
    sel.addRange(range)
    if (sel.extend)
      sel.extend(head.node, head.offset)
    this.storeDOMState()
  }

  // Clear all DOM statefulness of the last node selection.
  clearNode() {
    if (this.lastNode) {
      this.lastNode.classList.remove("ProseMirror-selectednode")
      this.pm.content.classList.remove("ProseMirror-nodeselection")
      this.lastNode = null
      return true
    }
  }

  receivedFocus() {
    if (this.polling == null) this.startPolling()
  }
}

// ;; An editor selection. Can be one of two selection types:
// `TextSelection` and `NodeSelection`. Both have the properties
// listed here, but also contain more information (such as the
// selected [node](#NodeSelection.node) or the
// [head](#TextSelection.head) and [anchor](#TextSelection.anchor)).
export class Selection {
  // :: Pos #path=Selection.prototype.from
  // The start of the selection.

  // :: Pos #path=Selection.prototype.to
  // The end of the selection.

  // :: bool #path=Selection.empty
  // True if the selection is an empty text selection (head an anchor
  // are the same).

  // :: (other: Selection) → bool #path=Selection.eq
  // Test whether the selection is the same as another selection.

  // :: (doc: Node, mapping: Mappable) → Selection #path=Selection.map
  // Map this selection through a [mappable](#Mappable) thing. `doc`
  // should be the new document, to which we are mapping.
}

// ;; A text selection represents a classical editor
// selection, with a head (the moving side) and anchor (immobile
// side), both of which point into textblock nodes. It can be empty (a
// regular cursor position).
export class TextSelection extends Selection {
  // :: (Pos, ?Pos)
  // Construct a text selection. When `head` is not given, it defaults
  // to `anchor`.
  constructor(anchor, head) {
    super()
    // :: Pos
    // The selection's immobile side (does not move when pressing
    // shift-arrow).
    this.anchor = anchor
    // :: Pos
    // The selection's mobile side (the side that moves when pressing
    // shift-arrow).
    this.head = head || anchor
  }

  get inverted() { return this.anchor.cmp(this.head) > 0 }
  get from() { return this.inverted ? this.head : this.anchor }
  get to() { return this.inverted ? this.anchor : this.head }
  get empty() { return this.anchor.cmp(this.head) == 0 }

  eq(other) {
    return other instanceof TextSelection && !other.head.cmp(this.head) && !other.anchor.cmp(this.anchor)
  }

  map(doc, mapping) {
    let head = mapping.map(this.head).pos
    if (!doc.path(head.path).isTextblock)
      return findSelectionNear(doc, head)
    let anchor = mapping.map(this.anchor).pos
    return new TextSelection(doc.path(anchor.path).isTextblock ? anchor : head, head)
  }
}

// ;; A node selection is a selection that points at a
// single node. All nodes marked [selectable](#NodeType.selectable)
// can be the target of a node selection. In such an object, `from`
// and `to` point directly before and after the selected node.
export class NodeSelection extends Selection {
  // :: (Pos, Pos, Node)
  // Create a node selection. Does not verify the validity of its
  // arguments. Use `ProseMirror.setNodeSelection` for an easier,
  // error-checking way to create a node selection.
  constructor(from, to, node) {
    super()
    this.from = from
    this.to = to
    // :: Node The selected node.
    this.node = node
  }

  get empty() { return false }

  eq(other) {
    return other instanceof NodeSelection && !this.from.cmp(other.from)
  }

  map(doc, mapping) {
    let from = mapping.map(this.from, 1).pos
    let to = mapping.map(this.to, -1).pos
    if (Pos.samePath(from.path, to.path) && from.offset == to.offset - 1) {
      let node = doc.nodeAfter(from)
      if (node.type.selectable) return new NodeSelection(from, to, node)
    }
    return findSelectionNear(doc, from)
  }
}

export function rangeFromDOMLoose(pm) {
  if (!hasFocus(pm)) return null
  let sel = window.getSelection()
  return new TextSelection(posFromDOM(pm, sel.anchorNode, sel.anchorOffset, true),
                           posFromDOM(pm, sel.focusNode, sel.focusOffset, true))
}

export function hasFocus(pm) {
  let sel = window.getSelection()
  return sel.rangeCount && contains(pm.content, sel.anchorNode)
}

function findSelectionIn(doc, path, offset, dir, text) {
  let node = doc.path(path)
  if (node.isTextblock) return new TextSelection(new Pos(path, offset))

  for (let i = offset + (dir > 0 ? 0 : -1); dir > 0 ? i < node.size : i >= 0; i += dir) {
    let child = node.child(i)
    if (!text && child.type.contains == null && child.type.selectable)
      return new NodeSelection(new Pos(path, i), new Pos(path, i + 1), child)
    path.push(i)
    let inside = findSelectionIn(doc, path, dir < 0 ? child.size : 0, dir, text)
    if (inside) return inside
    path.pop()
  }
}

// FIXME we'll need some awareness of bidi motion when determining block start and end

export function findSelectionFrom(doc, pos, dir, text) {
  for (let path = pos.path.slice(), offset = pos.offset;;) {
    let found = findSelectionIn(doc, path, offset, dir, text)
    if (found) return found
    if (!path.length) break
    offset = path.pop() + (dir > 0 ? 1 : 0)
  }
}

export function findSelectionNear(doc, pos, bias = 1, text) {
  let result = findSelectionFrom(doc, pos, bias, text) || findSelectionFrom(doc, pos, -bias, text)
  if (!result) SelectionError("Searching for selection in invalid document " + doc)
  return result
}

export function findSelectionAtStart(node, path = [], text) {
  return findSelectionIn(node, path.slice(), 0, 1, text)
}

export function findSelectionAtEnd(node, path = [], text) {
  return findSelectionIn(node, path.slice(), node.size, -1, text)
}

export function verticalMotionLeavesTextblock(pm, pos, dir) {
  let dom = pathToDOM(pm.content, pos.path)
  let coords = coordsAtPos(pm, pos)
  for (let child = dom.firstChild; child; child = child.nextSibling) {
    if (child.nodeType != 1) continue
    let boxes = child.getClientRects()
    for (let i = 0; i < boxes.length; i++) {
      let box = boxes[i]
      if (dir < 0 ? box.bottom < coords.top : box.top > coords.bottom)
        return false
    }
  }
  return true
}
<|endoftext|>


<commit_before>module.exports = {
  normalizeEntityName: function() {
  },

  afterInstall: function() {
    return this.addBowerPackageToProject("scrollmagic", "~2.0.5");
  }
};
<commit_msg>Removes erroneous bower package inclusion in blueprint<commit_after>/* eslint-env node:true */
/* globals module */

module.exports = {
  normalizeEntityName: function() {}
};
<|endoftext|>


<commit_before>type RefluxActionChild = "progressed" | "completed" | "failed";

type RefluxActionOptions = {
  sync?: boolean;
  asyncResult?: boolean;
  children?: RefluxActionChild[];
  preEmit?: Function;
  shouldEmit?: (preEmitValue: any) => boolean;
};

type RefluxActionProps = {
  sync: boolean;
  triggerAsync: Function;
  trigger: Function;
  listen: Function;
  completed: RefluxAction;
  failed: RefluxAction;
  promise(promise: Promise): any;
  listenAndPromise(asyncOperation: (...payloads: any) => Promise): any;
  preEmit?: Function;
  shouldEmit?: (preEmitValue: any) => boolean;
};

type RefluxAction = Function & RefluxActionProps;

type RefluxStoreOptions = {
  init: Function;
};

declare class RefluxStore {
  listen: Function;
  trigger: Function;
  listenToMany(actions: {[key: string]: RefluxAction}): any;
  listenTo(action: RefluxAction, listener: Function): any;
  listenables: Object;
}

declare module reflux {

  declare function createAction(options?: RefluxActionOptions): RefluxAction;

  declare function createActions(options: string[] | {[key: string]: RefluxActionOptions;}): Object;

  declare function createStore(options: RefluxStoreOptions): RefluxStore;

}<commit_msg>better type for Store.listen<commit_after>type RefluxActionChild = "progressed" | "completed" | "failed";

type RefluxActionOptions = {
  sync?: boolean;
  asyncResult?: boolean;
  children?: RefluxActionChild[];
  preEmit?: Function;
  shouldEmit?: (preEmitValue: any) => boolean;
};

type RefluxActionProps = {
  sync: boolean;
  triggerAsync: Function;
  trigger: Function;
  listen: Function;
  completed: RefluxAction;
  failed: RefluxAction;
  promise(promise: Promise): any;
  listenAndPromise(asyncOperation: (...payloads: any) => Promise): any;
  preEmit?: Function;
  shouldEmit?: (preEmitValue: any) => boolean;
};

type RefluxAction = Function & RefluxActionProps;

type RefluxStoreOptions = {
  init: Function;
};

declare class RefluxStore {
  listen: (callback: Function) => (() => void); // unsubscribe()
  trigger: Function;
  listenToMany(actions: {[key: string]: RefluxAction}): any;
  listenTo(action: RefluxAction, listener: Function): any;
  listenables: Object;
}

declare module reflux {

  declare function createAction(options?: RefluxActionOptions): RefluxAction;

  declare function createActions(options: string[] | {[key: string]: RefluxActionOptions;}): Object;

  declare function createStore(options: RefluxStoreOptions): RefluxStore;

}<|endoftext|>


<commit_before>(function() {
  var parser = window.BetterMarkdown,
      MD = parser.Markdown,
      DialectHelpers = parser.DialectHelpers;

  function generateUniqueishIdentifier () {
    // Stolen from StackOverflow: http://stackoverflow.com/a/8809472
    var d = new Date().getTime();
    var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        var r = (d + Math.random()*16)%16 | 0;
        d = Math.floor(d/16);
        return (c=='x' ? r : (r&0x3|0x8)).toString(16);
    });
    return uuid;
  }

  function generateJsonML (label, contents, opts) {
    var myId = 'spoilerrific-' + generateUniqueishIdentifier();

    var wrappingDiv = ['div'].concat(contents);

    return [
      'div', { 'class': 'spoilerrific', 'data-prefix': opts.usingDefaultLabel ? 'yes' : 'no', 'data-suffix': opts.usingDefaultLabel ? 'no' : 'yes' },
      [
        'input', { 'type': 'checkbox', 'id': myId }
      ],
      [
        'label', { 'for': myId }, label
      ],
      wrappingDiv
    ];
  }

  // At the moment, Discourse's blocking mechanism seems to be broken
  // such that the below code will only accept block-level Markdown tags
  // (e.g. headers) if they appear as the very first item in the block
  // Therefore, as a (rather hackish) workaround, we recursively invoke
  // the ENTIRE markdown processing chain...
  //var emitter = function(contents, params) {
  //  params = params || '';
  //  var label = params.replace(/(^")|("$)/g, '') || 'FLARD inside!';
  //  return generateJsonML(label, contents);
  //};
  //Discourse.BBCode.register('spoiler', {noWrap: true}, emitter);

  Discourse.Dialect.replaceBlock({
    start: /\[spoiler1(=[^\[\]]+)?\]([\s\S]*)/igm,
    stop: /\[\/spoiler1\]/igm,
    rawContents: true, // this is documented, but doesn't seem to do anything
    emitter: function(blockContents, matches) {
      var params = matches[1] ? matches[1].replace(/^=/g, '') : '',
          label = params.replace(/(^")|("$)/g, ''),
          opts = {
            usingDefaultLabel: false,
          },
          inner = blockContents.join("\n\n"),
          innerTree = parser.toHTMLTree(inner, "Discourse");

      if (!label) {
          opts.usingDefaultLabel = true;
          label = Discourse.SiteSettings.spoiler_default_label;
      }

      if (!innerTree || innerTree.length === 0 || innerTree[0] != 'html') { // uh?
          return generateJsonML(label, inner, opts);
      }

        return generateJsonML(label, innerTree.slice(1), opts);
      }
    }
  });

  var spoilerrificRe = /^spoilerrific-[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[0-9a-f]{4}-[0-9a-f]{12}$/;
  Discourse.Markdown.whiteListTag('div', 'class', 'spoilerrific');
  Discourse.Markdown.whiteListTag('input', 'type', 'checkbox');
  Discourse.Markdown.whiteListTag('input', 'checked', 'checked');
  Discourse.Markdown.whiteListTag('input', 'id', spoilerrificRe);
  Discourse.Markdown.whiteListTag('label', 'for', spoilerrificRe);
  Discourse.Markdown.whiteListTag('label', 'data-prefix', /^(yes|no)$/);
  Discourse.Markdown.whiteListTag('label', 'data-suffix', /^(yes|no)$/);
})();

<commit_msg>some changes<commit_after>(function() {
  var parser = window.BetterMarkdown,
      MD = parser.Markdown,
      DialectHelpers = parser.DialectHelpers;

  function generateUniqueishIdentifier () {
    // Stolen from StackOverflow: http://stackoverflow.com/a/8809472
    var d = new Date().getTime();
    var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        var r = (d + Math.random()*16)%16 | 0;
        d = Math.floor(d/16);
        return (c=='x' ? r : (r&0x3|0x8)).toString(16);
    });
    return uuid;
  }

  function generateJsonML (label, contents, opts) {
    var myId = 'spoilerrific-' + generateUniqueishIdentifier();

    var wrappingDiv = ['div'].concat(contents);

    return [
      'div', { 'class': 'spoilerrific', 'data-prefix': opts.usingDefaultLabel ? 'yes' : 'no', 'data-suffix': opts.usingDefaultLabel ? 'no' : 'yes' },
      [
        'input', { 'type': 'checkbox', 'id': myId }
      ],
      [
        'label', { 'for': myId }, label
      ],
      wrappingDiv
    ];
  }

  // At the moment, Discourse's blocking mechanism seems to be broken
  // such that the below code will only accept block-level Markdown tags
  // (e.g. headers) if they appear as the very first item in the block
  // Therefore, as a (rather hackish) workaround, we recursively invoke
  // the ENTIRE markdown processing chain...
  //var emitter = function(contents, params) {
  //  params = params || '';
  //  var label = params.replace(/(^")|("$)/g, '') || 'FLARD inside!';
  //  return generateJsonML(label, contents);
  //};
  //Discourse.BBCode.register('spoiler', {noWrap: true}, emitter);

  Discourse.Dialect.replaceBlock({
    start: /\[spoiler(=[^\[\]]+)?\]([\s\S]*)/igm,
    stop: /\[\/spoiler\]/igm,
    rawContents: true, // this is documented, but doesn't seem to do anything
    emitter: function(blockContents, matches) {
      var params = matches[1] ? matches[1].replace(/^=/g, '') : '',
          label = params.replace(/(^")|("$)/g, ''),
          opts = {
            usingDefaultLabel: false,
          },
          inner = blockContents.join("\n\n"),
          innerTree = parser.toHTMLTree(inner, "Discourse");

      if (!label) {
          opts.usingDefaultLabel = true;
          label = Discourse.SiteSettings.spoiler_default_label;
      }

      if (!innerTree || innerTree.length === 0 || innerTree[0] != 'html') { // uh?
          return generateJsonML(label, inner, opts);
      }

      return generateJsonML(label, innerTree.slice(1), opts);
    }
  });

  var spoilerrificRe = /^spoilerrific-[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[0-9a-f]{4}-[0-9a-f]{12}$/;
  Discourse.Markdown.whiteListTag('div', 'class', 'spoilerrific');
  Discourse.Markdown.whiteListTag('input', 'type', 'checkbox');
  Discourse.Markdown.whiteListTag('input', 'checked', 'checked');
  Discourse.Markdown.whiteListTag('input', 'id', spoilerrificRe);
  Discourse.Markdown.whiteListTag('label', 'for', spoilerrificRe);
  Discourse.Markdown.whiteListTag('label', 'data-prefix', /^(yes|no)$/);
  Discourse.Markdown.whiteListTag('label', 'data-suffix', /^(yes|no)$/);
})();
<|endoftext|>


<commit_before>/**
 * Unified Dashboard Feature Tour.
 *
 * Site Kit by Google, Copyright 2021 Google LLC
 *
 * 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
 *
 *     https://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.
 */

/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';

/*
 * Internal dependencies
 */
import { VIEW_CONTEXT_DASHBOARD } from '../googlesitekit/constants';
import { isFeatureEnabled } from '../features';

const unifiedDashboard = {
	slug: 'unifiedDashboard',
	contexts: [ VIEW_CONTEXT_DASHBOARD ],
	version: '1.50.0',
	gaEventCategory: ( viewContext ) => `${ viewContext }_unified-dashboard`,
	checkRequirements: () => isFeatureEnabled( 'unifiedDashboard' ),
	steps: [
		{
			target: '.googlesitekit-navigation',
			title: __(
				'New! Navigate your dashboard easily with the dashboard tabs',
				'google-site-kit'
			),
			content: __(
				'Jump straight to the relevant section in your dashboard with just one click - no more scrolling.',
				'google-site-kit'
			),
			placement: 'bottom-start',
		},
		{
			target: '.googlesitekit-entity-search',
			title: __( 'Check stats for a specific post', 'google-site-kit' ),
			content: __(
				'Search by URL or by post title and your dashboard will be filtered to show stats just for that URL.',
				'google-site-kit'
			),
			placement: 'bottom-start',
		},
		{
			target: '.googlesitekit-widget--searchFunnel',
			title: __(
				"See trends over time for your site's Search metrics",
				'google-site-kit'
			),
			content: __(
				'The updated Search Funnel shows you a more comprehensive view of how traffic from Search is changing.',
				'google-site-kit'
			),
			placement: 'top',
		},
	],
};

export default unifiedDashboard;
<commit_msg>Bump year.<commit_after>/**
 * Unified Dashboard Feature Tour.
 *
 * Site Kit by Google, Copyright 2022 Google LLC
 *
 * 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
 *
 *     https://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.
 */

/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';

/*
 * Internal dependencies
 */
import { VIEW_CONTEXT_DASHBOARD } from '../googlesitekit/constants';
import { isFeatureEnabled } from '../features';

const unifiedDashboard = {
	slug: 'unifiedDashboard',
	contexts: [ VIEW_CONTEXT_DASHBOARD ],
	version: '1.50.0',
	gaEventCategory: ( viewContext ) => `${ viewContext }_unified-dashboard`,
	checkRequirements: () => isFeatureEnabled( 'unifiedDashboard' ),
	steps: [
		{
			target: '.googlesitekit-navigation',
			title: __(
				'New! Navigate your dashboard easily with the dashboard tabs',
				'google-site-kit'
			),
			content: __(
				'Jump straight to the relevant section in your dashboard with just one click - no more scrolling.',
				'google-site-kit'
			),
			placement: 'bottom-start',
		},
		{
			target: '.googlesitekit-entity-search',
			title: __( 'Check stats for a specific post', 'google-site-kit' ),
			content: __(
				'Search by URL or by post title and your dashboard will be filtered to show stats just for that URL.',
				'google-site-kit'
			),
			placement: 'bottom-start',
		},
		{
			target: '.googlesitekit-widget--searchFunnel',
			title: __(
				"See trends over time for your site's Search metrics",
				'google-site-kit'
			),
			content: __(
				'The updated Search Funnel shows you a more comprehensive view of how traffic from Search is changing.',
				'google-site-kit'
			),
			placement: 'top',
		},
	],
};

export default unifiedDashboard;
<|endoftext|>


<commit_before>// +----------------------------------------------------------------------+
// | Bitflux Editor                                                       |
// +----------------------------------------------------------------------+
// | Copyright (c) 2003 Bitflux GmbH                                      |
// +----------------------------------------------------------------------+
// | This software is published under the terms of the Apache Software    |
// | License a copy of which has been included with this distribution in  |
// | the LICENSE file and is available through the web at                 |
// | http://bitflux.ch/editor/license.html                                |
// +----------------------------------------------------------------------+
// | Author: Christian Stocker <chregu@bitflux.ch>                        |
// +----------------------------------------------------------------------+
//
// $Id: ElementVDOM.js,v 1.15 2004/01/19 01:38:48 chregu Exp $

function ElementVDOM(node) {
	this.node = node;
	this._allowedChildren = new Array();
	this.type = "RELAXNG_ELEMENT";
	this.canBeRoot = false;
	this.nextSibling = null;
	this.previousSibling = null;
	this.minOccurs = 1;
	this.maxOccurs = 1;
	this._attributes = new Array();
}

ElementVDOM.prototype = new NodeVDOM();

NodeVDOM.prototype.addAttributeNode = function(attribute) {
	this._attributes[attribute.name] = attribute;
}

ElementVDOM.prototype.__defineGetter__ (
	"hasAttributes",
	function() {
		for (var i in this.attributes) {
			return true;
		}
		return false;

	}
);

ElementVDOM.prototype.addAllowedChild = function(node) {
	this._allowedChildren[node.name] = node;
}

NodeVDOM.prototype.getAllAttributes = function () {
	var child = this.firstChild;
	var attr = this._attributes;
	while (child) {
		if (child.nodeName == "RELAXNG_REF" && child.DefineVDOM) {
			var AA = child.DefineVDOM.getAllAttributes()
			if (AA) {
				for (i in AA) {
					attr[AA[i].name]= AA[i];
					//attr.push(AA[i]);
				}
			}
		}
		child = child.nextSibling;
	}
	return attr;
}

ElementVDOM.prototype.__defineGetter__ (
	"attributes",
	function() {
		if (typeof this._cachedAttributes == "undefined") {

			this._cachedAttributes = this.getAllAttributes();
		}
		return this._cachedAttributes;
	}
	);

ElementVDOM.prototype.isValid = function(ctxt) {
	if (ctxt.node.localName == this.localName && ctxt.node.namespaceURI == this.namespaceURI) {

		var _attr = this.attributes;
		for(var i in _attr) {
			 _attr[i].isValid(ctxt);
		}
		ctxt.node.vdom = this;
		ctxt.nextVDOM();
		return true;
	} else {
		return false;
	}
}
<commit_msg>added a try/catch which should not be needed... investigate later<commit_after>// +----------------------------------------------------------------------+
// | Bitflux Editor                                                       |
// +----------------------------------------------------------------------+
// | Copyright (c) 2003 Bitflux GmbH                                      |
// +----------------------------------------------------------------------+
// | This software is published under the terms of the Apache Software    |
// | License a copy of which has been included with this distribution in  |
// | the LICENSE file and is available through the web at                 |
// | http://bitflux.ch/editor/license.html                                |
// +----------------------------------------------------------------------+
// | Author: Christian Stocker <chregu@bitflux.ch>                        |
// +----------------------------------------------------------------------+
//
// $Id$

function ElementVDOM(node) {
	this.node = node;
	this._allowedChildren = new Array();
	this.type = "RELAXNG_ELEMENT";
	this.canBeRoot = false;
	this.nextSibling = null;
	this.previousSibling = null;
	this.minOccurs = 1;
	this.maxOccurs = 1;
	this._attributes = new Array();
}

ElementVDOM.prototype = new NodeVDOM();

NodeVDOM.prototype.addAttributeNode = function(attribute) {
/* FIXME: This try/catch had to be inserted for making it work for MIT
should look into it, what really was the issue.. */
try {
	this._attributes[attribute.name] = attribute;
} catch(e) {};
}

ElementVDOM.prototype.__defineGetter__ (
	"hasAttributes",
	function() {
		for (var i in this.attributes) {
			return true;
		}
		return false;

	}
);

ElementVDOM.prototype.addAllowedChild = function(node) {
	this._allowedChildren[node.name] = node;
}

NodeVDOM.prototype.getAllAttributes = function () {
	var child = this.firstChild;
	var attr = this._attributes;
	while (child) {
		if (child.nodeName == "RELAXNG_REF" && child.DefineVDOM) {
			var AA = child.DefineVDOM.getAllAttributes()
			if (AA) {
				for (i in AA) {
					attr[AA[i].name]= AA[i];
					//attr.push(AA[i]);
				}
			}
		}
		child = child.nextSibling;
	}
	return attr;
}

ElementVDOM.prototype.__defineGetter__ (
	"attributes",
	function() {
		if (typeof this._cachedAttributes == "undefined") {

			this._cachedAttributes = this.getAllAttributes();
		}
		return this._cachedAttributes;
	}
	);

ElementVDOM.prototype.isValid = function(ctxt) {
	if (ctxt.node.localName == this.localName && ctxt.node.namespaceURI == this.namespaceURI) {

		var _attr = this.attributes;
		for(var i in _attr) {
			 _attr[i].isValid(ctxt);
		}
		ctxt.node.vdom = this;
		ctxt.nextVDOM();
		return true;
	} else {
		return false;
	}
}
<|endoftext|>


<commit_before>(function() {

var queryStringParam = /^\?(.*)/;
var namedParam    = /:([\w\d]+)/g;
var splatParam    = /\*([\w\d]+)/g;
var escapeRegExp  = /[-[\]{}()+?.,\\^$|#\s]/g;

_.extend(Backbone.Router.prototype, {
  getFragment : function(fragment, forcePushState, excludeQueryString) {
    if (fragment == null) {
      if (this._hasPushState || forcePushState) {
        fragment = window.location.pathname;
        var search = window.location.search;
        if (search) fragment += search;
      } else {
        fragment = window.location.hash;
      }
    }
    fragment = fragment.replace(hashStrip, '');
    if (excludeQueryString) {
      fragment = fragment.replace(queryStrip, '');
    }
    if (!fragment.indexOf(this.options.root)) fragment = fragment.substr(this.options.root.length);
    return fragment;
  },

  _routeToRegExp : function(route) {
    route = route.replace(escapeRegExp, "\\$&")
                 .replace(namedParam, "([^\/?]*)")
                 .replace(splatParam, "([^\?]*)");
    route += '([\?]{1}.*)?';
    return new RegExp('^' + route + '$');
  },

  /**
   * Given a route, and a URL fragment that it matches, return the array of
   * extracted parameters.
   */
  _extractParameters : function(route, fragment) {
    var params = route.exec(fragment).slice(1);

    // do we have an additional query string?
    var match = params.length && params[params.length-1] && params[params.length-1].match(queryStringParam);
    if (match) {
      var queryString = match[1];
      var data = {};
      if (queryString) {
        var keyValues = queryString.split('&');
        var self = this;
        _.each(keyValues, function(keyValue) {
          var arr = keyValue.split('=');
          if (arr.length > 1 && arr[1]) {
            self._setParamValue(arr[0], arr[1], data);
          }
        });
      }
      params[params.length-1] = data;
    }

    // decode params
    for (var i=1; i<params.length; i++) {
      if (_.isString(params[i])) {
        params[i] = decodeURIComponent(params[i]);
      }
    }

    return params;
  },

  /**
   * Set the parameter value on the data hash
   */
  _setParamValue : function(key, value, data) {
    // use '.' to define hash separators
    var parts = key.split('.');
    var _data = data;
    for (var i=0; i<parts.length; i++) {
      var part = parts[i];
      if (i === parts.length-1) {
        // set the value
        _data[part] = this._decodeParamValue(value, _data[part]);
      } else {
        _data = _data[part] = _data[part] || {};
      }
    }
  },

  /**
   * Decode an individual parameter value (or list of values)
   * @param value the complete value
   * @param currentValue the currently known value (or list of values)
   */
  _decodeParamValue : function(value, currentValue) {
    // '|' will indicate an array.  Array with 1 value is a=|b - multiple values can be a=b|c
    if (value.indexOf('|') >= 0) {
      var values = value.split('|');
      // clean it up
      for (var i=values.length-1; i>=0; i--) {
        if (!values[i]) {
          values.splice(i, 1);
        } else {
          values[i] = decodeURIComponent(values[i])
        }
      }
      return values;
    }
    if (!currentValue) {
      return decodeURIComponent(value);
    } else if (_.isArray(currentValue)) {
      currentValue.push(value);
      return currentValue;
    } else {
      return [currentValue, value];
    }
  },

  /**
   * Return the route fragment with queryParameters serialized to query parameter string
   */
  toFragment: function(route, queryParameters) {
    if (queryParameters) {
      if (!_.isString(queryParameters)) {
        queryParameters = this._toQueryString(queryParameters);
      }
      route += '?' + queryParameters;
    }
    return route;
  },

  /**
   * Serialize the val hash to query parameters and return it.  Use the namePrefix to prefix all param names (for recursion)
   */
  _toQueryString: function(val, namePrefix) {
    if (!val) return '';
    namePrefix = namePrefix || '';
    var rtn = '';
    for (var name in val) {
      var _val = val[name];
      if (_.isString(_val) || _.isNumber(_val) || _.isBoolean(_val) || _.isDate(_val)) {
        // primitave type
        _val = this._toQueryParam(_val);
        if (_.isBoolean(_val) || _val) {
          rtn += (rtn ? '&' : '') + this._toQueryParamName(name, namePrefix) + '=' + encodeURIComponent(_val).replace('|', '%7C');
        }
      } else if (_.isArray(_val)) {
        // arrrays use | separator
        var str = '';
        for (var i in _val) {
          var param = this._toQueryParam(_val[i]);
          if (_.isBoolean(param) || param) {
            str += '|' + encodeURIComponent(param).replace('|', '%7C');
          }
        }
        if (str) {
          rtn += (rtn ? '&' : '') + this._toQueryParamName(name, namePrefix) + '=' + str;
        }
      } else {
        // dig into hash
        var result = this._toQueryString(_val, this._toQueryParamName(name, namePrefix, true));
        if (result) {
          rtn += (rtn ? '&' : '') + result;
        }
      }
    }
    return rtn;
  },

  /**
   * return the actual parameter name
   * @param name the parameter name
   * @param namePrefix the prefix to the name
   * @param createPrefix true if we're creating a name prefix, false if we're creating the name
   */
  _toQueryParamName: function(name, prefix, isPrefix) {
    return (prefix + name + (isPrefix ? '.' : ''));
  },

  /**
   * Return the string representation of the param used for the query string
   */
  _toQueryParam: function (param) {
    if (_.isNull(param) || _.isUndefined(param)) {
      return null;
    }
    if (_.isDate(param)) {
      return param.getDate().getTime();
    }
    return param;
  }
});
})();<commit_msg>decode first parameter as well<commit_after>(function() {

var queryStringParam = /^\?(.*)/;
var namedParam    = /:([\w\d]+)/g;
var splatParam    = /\*([\w\d]+)/g;
var escapeRegExp  = /[-[\]{}()+?.,\\^$|#\s]/g;

_.extend(Backbone.Router.prototype, {
  getFragment : function(fragment, forcePushState, excludeQueryString) {
    if (fragment == null) {
      if (this._hasPushState || forcePushState) {
        fragment = window.location.pathname;
        var search = window.location.search;
        if (search) fragment += search;
      } else {
        fragment = window.location.hash;
      }
    }
    fragment = fragment.replace(hashStrip, '');
    if (excludeQueryString) {
      fragment = fragment.replace(queryStrip, '');
    }
    if (!fragment.indexOf(this.options.root)) fragment = fragment.substr(this.options.root.length);
    return fragment;
  },

  _routeToRegExp : function(route) {
    route = route.replace(escapeRegExp, "\\$&")
                 .replace(namedParam, "([^\/?]*)")
                 .replace(splatParam, "([^\?]*)");
    route += '([\?]{1}.*)?';
    return new RegExp('^' + route + '$');
  },

  /**
   * Given a route, and a URL fragment that it matches, return the array of
   * extracted parameters.
   */
  _extractParameters : function(route, fragment) {
    var params = route.exec(fragment).slice(1);

    // do we have an additional query string?
    var match = params.length && params[params.length-1] && params[params.length-1].match(queryStringParam);
    if (match) {
      var queryString = match[1];
      var data = {};
      if (queryString) {
        var keyValues = queryString.split('&');
        var self = this;
        _.each(keyValues, function(keyValue) {
          var arr = keyValue.split('=');
          if (arr.length > 1 && arr[1]) {
            self._setParamValue(arr[0], arr[1], data);
          }
        });
      }
      params[params.length-1] = data;
    }

    // decode params
    for (var i=0; i<params.length; i++) {
      if (_.isString(params[i])) {
        params[i] = decodeURIComponent(params[i]);
      }
    }

    return params;
  },

  /**
   * Set the parameter value on the data hash
   */
  _setParamValue : function(key, value, data) {
    // use '.' to define hash separators
    var parts = key.split('.');
    var _data = data;
    for (var i=0; i<parts.length; i++) {
      var part = parts[i];
      if (i === parts.length-1) {
        // set the value
        _data[part] = this._decodeParamValue(value, _data[part]);
      } else {
        _data = _data[part] = _data[part] || {};
      }
    }
  },

  /**
   * Decode an individual parameter value (or list of values)
   * @param value the complete value
   * @param currentValue the currently known value (or list of values)
   */
  _decodeParamValue : function(value, currentValue) {
    // '|' will indicate an array.  Array with 1 value is a=|b - multiple values can be a=b|c
    if (value.indexOf('|') >= 0) {
      var values = value.split('|');
      // clean it up
      for (var i=values.length-1; i>=0; i--) {
        if (!values[i]) {
          values.splice(i, 1);
        } else {
          values[i] = decodeURIComponent(values[i])
        }
      }
      return values;
    }
    if (!currentValue) {
      return decodeURIComponent(value);
    } else if (_.isArray(currentValue)) {
      currentValue.push(value);
      return currentValue;
    } else {
      return [currentValue, value];
    }
  },

  /**
   * Return the route fragment with queryParameters serialized to query parameter string
   */
  toFragment: function(route, queryParameters) {
    if (queryParameters) {
      if (!_.isString(queryParameters)) {
        queryParameters = this._toQueryString(queryParameters);
      }
      route += '?' + queryParameters;
    }
    return route;
  },

  /**
   * Serialize the val hash to query parameters and return it.  Use the namePrefix to prefix all param names (for recursion)
   */
  _toQueryString: function(val, namePrefix) {
    if (!val) return '';
    namePrefix = namePrefix || '';
    var rtn = '';
    for (var name in val) {
      var _val = val[name];
      if (_.isString(_val) || _.isNumber(_val) || _.isBoolean(_val) || _.isDate(_val)) {
        // primitave type
        _val = this._toQueryParam(_val);
        if (_.isBoolean(_val) || _val) {
          rtn += (rtn ? '&' : '') + this._toQueryParamName(name, namePrefix) + '=' + encodeURIComponent(_val).replace('|', '%7C');
        }
      } else if (_.isArray(_val)) {
        // arrrays use | separator
        var str = '';
        for (var i in _val) {
          var param = this._toQueryParam(_val[i]);
          if (_.isBoolean(param) || param) {
            str += '|' + encodeURIComponent(param).replace('|', '%7C');
          }
        }
        if (str) {
          rtn += (rtn ? '&' : '') + this._toQueryParamName(name, namePrefix) + '=' + str;
        }
      } else {
        // dig into hash
        var result = this._toQueryString(_val, this._toQueryParamName(name, namePrefix, true));
        if (result) {
          rtn += (rtn ? '&' : '') + result;
        }
      }
    }
    return rtn;
  },

  /**
   * return the actual parameter name
   * @param name the parameter name
   * @param namePrefix the prefix to the name
   * @param createPrefix true if we're creating a name prefix, false if we're creating the name
   */
  _toQueryParamName: function(name, prefix, isPrefix) {
    return (prefix + name + (isPrefix ? '.' : ''));
  },

  /**
   * Return the string representation of the param used for the query string
   */
  _toQueryParam: function (param) {
    if (_.isNull(param) || _.isUndefined(param)) {
      return null;
    }
    if (_.isDate(param)) {
      return param.getDate().getTime();
    }
    return param;
  }
});
})();<|endoftext|>


<commit_before>(function (factory) {

  // Check for AMD.
  if (typeof define === 'function' && define.amd) {
    define(['underscore', 'backbone'], factory);
  }

  // Next for Node.js or CommonJS.
  else if (typeof exports === 'object') {
    factory(require('underscore'), require('backbone'));
  }

  // Finally, as a browser global.
  else {
    factory(_, Backbone);
  }

}(function (_, Backbone) {

  // Backbone.View Mixins
  // --------------------

  _.extend(Backbone.View.prototype, {

    /**
    * ViewManager has a default render function that will render
    * if there is a template function defined in the view.  If serializeData is
    * implemented its' return value will be passed to the template funcion otherwise
    * this will be passed.
    *
    * Implement an 'onRender'
    * function to extend the render functionality.  It returns 'this' to support
    * chaining. This will trigger a 'rendered' event.
    *
    * By setting attachToTemplate render will attach the view to the top element of
    * the template. Using this option will remove the default behavior of Backbone
    * that creates all views with a default div tag.
    * @render
    */
    render: function() {
        if (this.template && _.isFunction(this.template)) {
            var data = _.isFunction(this.serializeData) ? this.serializeData() : this;
            var $template = $(this.template(data));
            if (this.attachToTemplate && $template.length === 1) {
                // swap out the view on the top level element to avoid duplication
                this.$el.replaceWith($template);

                // delegate events
                this.setElement($template);
            } else {
                this.$el.html($template);
            }
        }

        this.restoreSubViews();

        if (this.onRender && _.isFunction(this.onRender)) {
            this.onRender.apply(this, arguments);
        }
        this.trigger('rendered',this);
        return this;
    },

    /**
    * Use setView to replace the entire contents of the view with a new view.
    * this function will also remove all views currently contained within the view.
    * This will trigger a 'shown' event.
    * @setView
    * @param {Backbone.View} view - The view to use
    * @param {object} options - Set options.emptyDOM to true in cases where the DOM
    * that the view is attached is managed by something other than Backbone
    */
    setView: function(view, options) {
        this.removeSubViews();
        // this is needed for cases where the DOM is changed by something
        // other than what is managed by backbone
        if (options && options.emptyDOM) {
            this.$el.empty();
        }
        this.addSubView({view: view, selector: this.$el});
        return view;
    },

    /**
    * Use getView to retrieve the primary subView
    * @getView
    */
    getView: function() {
        if (this._subViews && this._subViews.length > 0) {
            return this._subViews[0];
        }
    },

    /**
    * AddSubView is used to render and add a subview to an parent view. If you need
    * to perform some work after the view is added to the DOM you can implement a
    * 'onShow' function.  This will also trigger a 'shown' event.
    * @addSubView
    * @param {object} options - An option object with a view and a selector
    */
    addSubView: function(options) {
        if (!options || !options.view) {
            throw new Error('Missing required view option');
        }

        if (!this._subViews) {
            this._subViews = [options];
        }
        else {
            this._subViews.push(options);
        }
        this.listenTo(options.view,'closed',this._removeSubView);

        return this._showSubView(options);
    },

    /**
    * RestoreSubViews can be used to restore views to the DOM that have been
    * removed as a result of the parent view rerendering
    * @restoreSubViews
    */
    restoreSubViews: function() {
      // restore the sub views to the dom
      _.each(this._subViews,this._showSubView,this);
    },

    _showSubView: function(options) {
      var selector;
      if (_.isObject(options.selector)) {
          selector = options.selector;
      }
      else if (_.isString(options.selector)) {
          selector = this.$(options.selector);
      }
      else {
          selector = this.$el;
      }

      options.view.render();
      if (options.location === 'prepend') {
          selector.prepend(options.view.el);
      }
      else if (options.location === 'before') {
          selector.before(options.view.el);
      }
      else if (options.location === 'after') {
          selector.after(options.view.el);
      }
      else {
          selector.append(options.view.el);
      }

      if (options.view.onShow && _.isFunction(options.view.onShow)) {
          options.view.onShow.apply(options.view,arguments);
      }
      options.view.trigger('shown',this);

      return options.view;
    },

    /**
    * Retrieve the current number of sub views.
    * @getSubViewCount
    */
    getSubViewCount: function() {
      return this._subViews ? this._subViews.length : 0;
    },

    /**
    * Removes all sub-views from a parent
    * @removeSubViews
    */
    removeSubViews: function() {
        _.each(this._subViews, function(subView, i) {
            subView.view.close();
        }, this);
        this._subViews = [];
    },

    _removeSubView: function(view) {
      var viewOption = _.findWhere(this._subViews, {view: view});
      var index = this._subViews.indexOf(viewOption);
      if (index > -1) {
        this._subViews.splice(index,1);
      }
    },

    /**
    * RemoveSubViewForModel will close the first sub view that has the attched
    * model.  As a result a 'closed' event will be fired for the view and it
    * will be removed from the DOM.
    * @removeSubViewForModel
    * @param {object} model - The model associated with the view
    */
    removeSubViewForModel: function(model) {
        _.find(this._subViews, function(subView, index) {
          if (subView.view.model && subView.view.model === model) {
              subView.view.close();
              return true;
          }
        }, this);
    },

    /**
    * Helper function to return the attribute of a model if the model is assigned
    * @getAttr
    * @params {string} attribute - The name of the attribute
    */
    getAttr: function(attribute) {
        if (this.model) {
            return this.model.get(attribute);
        }
    },

    /**
    * Return all the fields and their value of a form as an object
    * @serializeForm
    * @params {string} selector - A jquery selector identifying the form
    */
    serializeForm: function(selector) {
        var result = {};
        var fields = this.$(selector).serializeArray();
        _.each(fields, function(field) {
            if (result[field.name]) {
                if (!result[field.name].push) {
                    result[field.name] = [result[field.name]];
                }
                result[field.name].push(field.value || '');
            } else {
                result[field.name] = field.value || '';
            }
        });
        return result;
    },

    /**
    * Remove all subviews and safely remove this view from the DOM. Implement an
    * 'onClose' function for any additional clean up that is required before
    * removing the view from the DOM.  This will trigger a 'closed' event just
    * before removing from the DOM.
    * @close
    */
    close: function() {
        if (this.onClose && _.isFunction(this.onClose)) {
            this.onClose.apply(this, arguments);
        }
        this.removeSubViews();
        this.remove();
        this.trigger('closed',this);
        this.unbind();
    }

  });

}));
<commit_msg>fix a bug with the last view not getting removed from the subviews<commit_after>(function (factory) {

  // Check for AMD.
  if (typeof define === 'function' && define.amd) {
    define(['underscore', 'backbone'], factory);
  }

  // Next for Node.js or CommonJS.
  else if (typeof exports === 'object') {
    factory(require('underscore'), require('backbone'));
  }

  // Finally, as a browser global.
  else {
    factory(_, Backbone);
  }

}(function (_, Backbone) {

  // Backbone.View Mixins
  // --------------------

  _.extend(Backbone.View.prototype, {

    /**
    * ViewManager has a default render function that will render
    * if there is a template function defined in the view.  If serializeData is
    * implemented its' return value will be passed to the template funcion otherwise
    * this will be passed.
    *
    * Implement an 'onRender'
    * function to extend the render functionality.  It returns 'this' to support
    * chaining. This will trigger a 'rendered' event.
    *
    * By setting attachToTemplate render will attach the view to the top element of
    * the template. Using this option will remove the default behavior of Backbone
    * that creates all views with a default div tag.
    * @render
    */
    render: function() {
        if (this.template && _.isFunction(this.template)) {
            var data = _.isFunction(this.serializeData) ? this.serializeData() : this;
            var $template = $(this.template(data));
            if (this.attachToTemplate && $template.length === 1) {
                // swap out the view on the top level element to avoid duplication
                this.$el.replaceWith($template);

                // delegate events
                this.setElement($template);
            } else {
                this.$el.html($template);
            }
        }

        this.restoreSubViews();

        if (this.onRender && _.isFunction(this.onRender)) {
            this.onRender.apply(this, arguments);
        }
        this.trigger('rendered',this);
        return this;
    },

    /**
    * Use setView to replace the entire contents of the view with a new view.
    * this function will also remove all views currently contained within the view.
    * This will trigger a 'shown' event.
    * @setView
    * @param {Backbone.View} view - The view to use
    * @param {object} options - Set options.emptyDOM to true in cases where the DOM
    * that the view is attached is managed by something other than Backbone
    */
    setView: function(view, options) {
        this.removeSubViews();
        // this is needed for cases where the DOM is changed by something
        // other than what is managed by backbone
        if (options && options.emptyDOM) {
            this.$el.empty();
        }
        this.addSubView({view: view, selector: this.$el});
        return view;
    },

    /**
    * Use getView to retrieve the primary subView
    * @getView
    */
    getView: function() {
        if (this._subViews && this._subViews.length > 0) {
            return this._subViews[0];
        }
    },

    /**
    * AddSubView is used to render and add a subview to an parent view. If you need
    * to perform some work after the view is added to the DOM you can implement a
    * 'onShow' function.  This will also trigger a 'shown' event.
    * @addSubView
    * @param {object} options - An option object with a view and a selector
    */
    addSubView: function(options) {
        if (!options || !options.view) {
            throw new Error('Missing required view option');
        }

        if (!this._subViews) {
            this._subViews = [options];
        }
        else {
            this._subViews.push(options);
        }
        this.listenTo(options.view,'closed',this._removeSubView);

        return this._showSubView(options);
    },

    /**
    * RestoreSubViews can be used to restore views to the DOM that have been
    * removed as a result of the parent view rerendering
    * @restoreSubViews
    */
    restoreSubViews: function() {
      // restore the sub views to the dom
      _.each(this._subViews,this._showSubView,this);
    },

    _showSubView: function(options) {
      var selector;
      if (_.isObject(options.selector)) {
          selector = options.selector;
      }
      else if (_.isString(options.selector)) {
          selector = this.$(options.selector);
      }
      else {
          selector = this.$el;
      }

      options.view.render();
      if (options.location === 'prepend') {
          selector.prepend(options.view.el);
      }
      else if (options.location === 'before') {
          selector.before(options.view.el);
      }
      else if (options.location === 'after') {
          selector.after(options.view.el);
      }
      else {
          selector.append(options.view.el);
      }

      if (options.view.onShow && _.isFunction(options.view.onShow)) {
          options.view.onShow.apply(options.view,arguments);
      }
      options.view.trigger('shown',this);

      return options.view;
    },

    /**
    * Retrieve the current number of sub views.
    * @getSubViewCount
    */
    getSubViewCount: function() {
      return this._subViews ? this._subViews.length : 0;
    },

    /**
    * Removes all sub-views from a parent
    * @removeSubViews
    */
    removeSubViews: function() {
        _.each(this._subViews, function(subView) {
            subView.view.close();
        });
        this._subViews = [];
    },

    _removeSubView: function(view) {
      var viewOption = _.findWhere(this._subViews, {view: view});
      var index = this._subViews.indexOf(viewOption);
      if (index > -1) {
        this._subViews.splice(index,1);
      }
    },

    /**
    * RemoveSubViewForModel will close the first sub view that has the attched
    * model.  As a result a 'closed' event will be fired for the view and it
    * will be removed from the DOM.
    * @removeSubViewForModel
    * @param {object} model - The model associated with the view
    */
    removeSubViewForModel: function(model) {
        _.find(this._subViews, function(subView, index) {
          if (subView.view.model && subView.view.model === model) {
              subView.view.close();
              return true;
          }
        }, this);
    },

    /**
    * Helper function to return the attribute of a model if the model is assigned
    * @getAttr
    * @params {string} attribute - The name of the attribute
    */
    getAttr: function(attribute) {
        if (this.model) {
            return this.model.get(attribute);
        }
    },

    /**
    * Return all the fields and their value of a form as an object
    * @serializeForm
    * @params {string} selector - A jquery selector identifying the form
    */
    serializeForm: function(selector) {
        var result = {};
        var fields = this.$(selector).serializeArray();
        _.each(fields, function(field) {
            if (result[field.name]) {
                if (!result[field.name].push) {
                    result[field.name] = [result[field.name]];
                }
                result[field.name].push(field.value || '');
            } else {
                result[field.name] = field.value || '';
            }
        });
        return result;
    },

    /**
    * Remove all subviews and safely remove this view from the DOM. Implement an
    * 'onClose' function for any additional clean up that is required before
    * removing the view from the DOM.  This will trigger a 'closed' event just
    * before removing from the DOM.
    * @close
    */
    close: function() {
        if (this.onClose && _.isFunction(this.onClose)) {
            this.onClose.apply(this, arguments);
        }
        this.removeSubViews();
        this.unbind();
        this.remove();
        this.trigger('closed',this);
    }

  });

}));
<|endoftext|>


<commit_before>test(
  'Atomic Test: styles.StyleConversionsTest',

  [
    'ephox.agar.api.RawAssertions',
    'tinymce.themes.mobile.util.StyleConversions'
  ],

  function (RawAssertions, StyleConversions) {
    var check = function (label, expected, input) {
      var output = StyleConversions.getAlpha(input);
      RawAssertions.assertEq('StyleConversions.getAlpha (' + label + ')', expected, output);
    };

    check(
      'Empty input',
      {
        menus: { },
        expansions: { },
        items: [ ]
      },
      [ ]
    );

    check(
      'Input with one item',
      {
        menus: { },
        expansions: { },
        items: [
          { title: 'alpha' }
        ]
      },
      [
        { title: 'alpha' }
      ]
    );

  }
);
<commit_msg>TM-35-settings: TM-35-settings: test with three flat items<commit_after>test(
  'Atomic Test: styles.StyleConversionsTest',

  [
    'ephox.agar.api.RawAssertions',
    'tinymce.themes.mobile.util.StyleConversions'
  ],

  function (RawAssertions, StyleConversions) {
    var check = function (label, expected, input) {
      var output = StyleConversions.getAlpha(input);
      RawAssertions.assertEq('StyleConversions.getAlpha (' + label + ')', expected, output);
    };

    check(
      'Empty input',
      {
        menus: { },
        expansions: { },
        items: [ ]
      },
      [ ]
    );

    check(
      'Input with one flat item',
      {
        menus: { },
        expansions: { },
        items: [
          { title: 'alpha' }
        ]
      },
      [
        { title: 'alpha' }
      ]
    );

    check(
      'Input with three flat items',
      {
        menus: { },
        expansions: { },
        items: [
          { title: 'alpha' },
          { title: 'beta' },
          { title: 'gamma' }
        ]
      },
      [
        { title: 'alpha' },
        { title: 'beta' },
        { title: 'gamma' }
      ]
    );

  }
);
<|endoftext|>