<commit_before>import {
  defaultState,
  firstRender,
  ids,
  raiseChangeEvents,
  render,
  setState,
  state,
  stateEffects,
  template,
} from "../../src/base/internal.js";
import SlotContentMixin from "../../src/base/SlotContentMixin.js";
import { templateFrom } from "../../src/core/htmlLiterals.js";
import ReactiveElement from "../../src/core/ReactiveElement.js";

/**
 * Lightweight demo/story browser
 */
export default class StoryBrowser extends SlotContentMixin(ReactiveElement) {
  get [defaultState]() {
    return Object.assign(super[defaultState], {
      defaultPath: null,
      links: [],
      path: getPathFromHash(window.location.hash),
    });
  }

  [render](changed) {
    super[render](changed);

    if (this[firstRender]) {
      // Clicking close button navigates to current page (without frame).
      this[ids].closeButton.addEventListener("click", () => {
        this[raiseChangeEvents] = true;
        window.location = this[state].path;
        this[raiseChangeEvents] = false;
      });

      // Refresh title on page load.
      this[ids].frame.addEventListener("load", () => {
        document.title = this[ids].frame.contentDocument.title;
      });

      // When hash changes, load the indicated page.
      window.addEventListener("hashchange", () => {
        this[raiseChangeEvents] = true;
        const path =
          getPathFromHash(window.location.hash) || this[state].defaultPath;
        this[setState]({ path });
        this[raiseChangeEvents] = false;
      });
    }

    if (changed.path) {
      const { path } = this[state];

      // Show the indicated story in the frame.
      if (this[ids].frame.contentDocument.location.pathname !== path) {
        // Use `replace` to avoid affecting browser history.
        this[ids].frame.contentWindow.location.replace(path);
      }
    }

    // Highlight any navigation links that point to this page.
    if (changed.links || changed.path) {
      const { links, path } = this[state];
      if (links && path) {
        // Mark any links which are current.
        const expectedHash = `#path=${path}`;
        links.forEach((link) => {
          const current = link.hash === expectedHash;
          link.classList.toggle("current", current);
        });
      }
    }
  }

  [stateEffects](state, changed) {
    const effects = super[stateEffects]
      ? super[stateEffects](state, changed)
      : {};

    // Extract links from content.
    if (changed.content && state.content) {
      const links = [];
      state.content.forEach((element) => {
        if (element instanceof HTMLAnchorElement) {
          // Content element is itself a link.
          links.push(element);
        }
        if (element instanceof HTMLElement) {
          // Add any links inside content element
          links.push(...element.querySelectorAll("a"));
        }
      });
      Object.assign(effects, { links });
    }

    // Use first link as default path.
    if (changed.links && state.links.length > 0) {
      const defaultPath = getPathFromHash(state.links[0].hash);
      Object.assign(effects, { defaultPath });
    }

    // Use the default path as a path if we don't have a path already.
    if (changed.defaultPath && state.defaultPath && !state.path) {
      Object.assign(effects, {
        path: state.defaultPath,
      });
    }

    return effects;
  }

  get [template]() {
    return templateFrom.html`

        <button id="closeButton">⨉</button>
        <slot></slot>

    `;
  }
}

// Get a URL hash, return the path.
function getPathFromHash(hash) {
  const match = /#.*path=(?<path>[^&]+)/.exec(hash);
  return match?.groups?.path;
}
<commit_msg>Scroll current link into view.<commit_after>import {
  defaultState,
  firstRender,
  ids,
  raiseChangeEvents,
  render,
  setState,
  state,
  stateEffects,
  template,
} from "../../src/base/internal.js";
import SlotContentMixin from "../../src/base/SlotContentMixin.js";
import { templateFrom } from "../../src/core/htmlLiterals.js";
import ReactiveElement from "../../src/core/ReactiveElement.js";

/**
 * Lightweight demo/story browser
 */
export default class StoryBrowser extends SlotContentMixin(ReactiveElement) {
  get [defaultState]() {
    return Object.assign(super[defaultState], {
      defaultPath: null,
      links: [],
      path: getPathFromHash(window.location.hash),
    });
  }

  [render](changed) {
    super[render](changed);

    if (this[firstRender]) {
      // Clicking close button navigates to current page (without frame).
      this[ids].closeButton.addEventListener("click", () => {
        this[raiseChangeEvents] = true;
        window.location = this[state].path;
        this[raiseChangeEvents] = false;
      });

      // Refresh title on page load.
      this[ids].frame.addEventListener("load", () => {
        document.title = this[ids].frame.contentDocument.title;
      });

      // When hash changes, load the indicated page.
      window.addEventListener("hashchange", () => {
        this[raiseChangeEvents] = true;
        const path =
          getPathFromHash(window.location.hash) || this[state].defaultPath;
        this[setState]({ path });
        this[raiseChangeEvents] = false;
      });
    }

    if (changed.path) {
      const { path } = this[state];
      // Show the indicated story in the frame.
      if (this[ids].frame.contentDocument.location.pathname !== path) {
        // Use `replace` to avoid affecting browser history.
        this[ids].frame.contentWindow.location.replace(path);
      }
    }

    // Highlight any navigation links that point to this page.
    if (changed.links || changed.path) {
      const { links, path } = this[state];
      let currentLink;
      if (links && path) {
        // Mark any links which are current.
        const expectedHash = `#path=${path}`;
        links.forEach((link) => {
          const current = link.hash === expectedHash;
          link.classList.toggle("current", current);
          if (current && !currentLink) {
            currentLink = link;
          }
        });
        // Scroll the (first) current link into view.
        if (currentLink) {
          currentLink.scrollIntoView({ block: "nearest" });
        }
      }
    }
  }

  [stateEffects](state, changed) {
    const effects = super[stateEffects]
      ? super[stateEffects](state, changed)
      : {};

    // Extract links from content.
    if (changed.content && state.content) {
      const links = [];
      state.content.forEach((element) => {
        if (element instanceof HTMLAnchorElement) {
          // Content element is itself a link.
          links.push(element);
        }
        if (element instanceof HTMLElement) {
          // Add any links inside content element
          links.push(...element.querySelectorAll("a"));
        }
      });
      Object.assign(effects, { links });
    }

    // Use first link as default path.
    if (changed.links && state.links.length > 0) {
      const defaultPath = getPathFromHash(state.links[0].hash);
      Object.assign(effects, { defaultPath });
    }

    // Use the default path as a path if we don't have a path already.
    if (changed.defaultPath && state.defaultPath && !state.path) {
      Object.assign(effects, {
        path: state.defaultPath,
      });
    }

    return effects;
  }

  get [template]() {
    return templateFrom.html`

        <button id="closeButton">⨉</button>
        <slot></slot>

    `;
  }
}

// Get a URL hash, return the path.
function getPathFromHash(hash) {
  const match = /#.*path=(?<path>[^&]+)/.exec(hash);
  return match?.groups?.path;
}
<|endoftext|>


<commit_before>import React from "react-native";
import Icon from "./icon";
import AvatarController from "../controllers/avatar-controller";
import TouchFeedback from "./touch-feedback";
import routes from "../utils/routes";
import timeUtils from "../../lib/time-utils";

const {
	StyleSheet,
	View,
	Text,
	TouchableHighlight,
	PixelRatio
} = React;

const styles = StyleSheet.create({
	item: {
		backgroundColor: "#fff",
		borderColor: "rgba(0, 0, 0, .08)",
		borderBottomWidth: 1 / PixelRatio.get()
	},
	note: {
		flexDirection: "row"
	},
	avatar: {
		height: 36,
		width: 36,
		borderRadius: 18,
		backgroundColor: "rgba(0, 0, 0, .16)",
		marginHorizontal: 16,
		marginVertical: 12
	},
	image: {
		flex: 1,
		resizeMode: "cover",
		borderRadius: 18
	},
	content: {
		flex: 1,
		marginVertical: 8
	},
	title: {
		lineHeight: 21,
		color: "#999"
	},
	summary: {
		lineHeight: 18,
		fontSize: 12,
		color: "#999"
	},
	strong: {
		color: "#555"
	},
	timestampContainer: {
		flexDirection: "row"
	},
	timestamp: {
		fontSize: 11,
		marginVertical: 2,
		color: "#aaa",
		marginLeft: 4,
		paddingHorizontal: 4
	},
	icon: {
		fontSize: 12,
		color: "#000",
		marginVertical: 4,
		opacity: 0.3
	},
	close: {
		paddingVertical: 12,
		paddingHorizontal: 16
	}
});

export default class NotificationCenterItem extends React.Component {
	_extractPart(note, index) {
		return typeof note.group === "string" ? note.group.split("/")[index] : null;
	}

	_getThread(note) {
		const thread = this._extractPart(note, 1);

		return (thread === "all" || !thread) ? null : thread;
	}

	_getRoom(note) {
		return this._extractPart(note, 0);
	}

	_getSummary(note) {
		const max = 3;

		const { noteData, noteType, count } = note;

		const room = this._getRoom(this.props.note);

		const summary = [];

		switch (noteType) {
		case "mention":
			if (count > max) {
				summary.push(<Text key={1} style={styles.strong}>{count}</Text>, " new mentions in");
			} else {
				summary.push(<Text key={1} style={styles.strong}>{noteData.from}</Text>, " mentioned you in");
			}

			if (noteData.title) {
				summary.push(" ", <Text key={2} style={styles.strong}>{noteData.title}</Text>);
			}

			summary.push(" - ", <Text key={3} style={styles.strong}>{room}</Text>);

			break;
		case "reply":
			if (count > max) {
				summary.push(<Text key={1} style={styles.strong}>{count}</Text>, " new replies");
			} else {
				summary.push(<Text key={1} style={styles.strong}>{noteData.from}</Text>, " replied");
			}

			if (noteData.title) {
				summary.push(" to ", <Text key={2} style={styles.strong}>{noteData.title}</Text>);
			}

			summary.push(" in ", <Text key={3} style={styles.strong}>{room}</Text>);

			break;
		case "thread":
			if (count > max) {
				summary.push(<Text key={1} style={styles.strong}>{count}</Text>, " new discussions");
			} else {
				summary.push(<Text key={1} style={styles.strong}>{noteData.from}</Text>, " started a discussion");

				if (noteData.title) {
					summary.push(" on ", <Text key={2} style={styles.strong}>{noteData.title}</Text>);
				}
			}

			summary.push(" in ", <Text key={3} style={styles.strong}>{room}</Text>);

			break;
		default:
			if (count > max) {
				summary.push(<Text key={1} style={styles.strong}>{count}</Text>, " new notifications");
			} else {
				summary.push("New notification from ", <Text key={1} style={styles.strong}>{noteData.from}</Text>);
			}

			summary.push(" in ", <Text key={2} style={styles.strong}>{room}</Text>);
		}

		return summary;
	}

	_onPress() {
		const { note, navigator } = this.props;

		const room = this._getRoom(note);
		const thread = this._getThread(note);

		switch (note.noteType) {
		case "mention":
		case "reply":
		case "thread":
			navigator.push(routes.chat({
				thread,
				room
			}));

			break;
		default:
			navigator.push(routes.room({ room }));
		}
	}

	_onDismiss() {
		this.props.dismissNote(this.props.note);
	}

	render() {
		const { note } = this.props;

		return (
			<View style={styles.item}>
				<TouchFeedback onPress={this._onPress.bind(this)}>
					<View style={styles.note}>
						<View style={styles.avatar}>
							<AvatarController
								size={36}
								nick={note.noteData.from}
								style={styles.image}
							/>
						</View>
						<View style={styles.content}>
							<View>
								<Text numberOfLines={5} style={styles.title} >{this._getSummary(note)}</Text>
							</View>
							<View>
								<Text numberOfLines={1} style={styles.summary} >{note.noteData.text}</Text>
							</View>
							<View style={styles.timestampContainer}>
								<Icon name="access-time" style={styles.icon} />
								<Text style={styles.timestamp}>{timeUtils.long(note.time)}</Text>
							</View>
						</View>
						<TouchableHighlight underlayColor="rgba(0, 0, 0, .08)" onPress={this._onDismiss.bind(this)}>
							<View style={styles.close}>
								<Icon name="close" style={styles.icon} />
							</View>
						</TouchableHighlight>
					</View>
				</TouchFeedback>
			</View>
		);
	}
}

NotificationCenterItem.propTypes = {
	note: React.PropTypes.shape({
		count: React.PropTypes.number,
		group: React.PropTypes.string.isRequired,
		noteType: React.PropTypes.string.isRequired,
		noteData: React.PropTypes.shape({
			title: React.PropTypes.string,
			text: React.PropTypes.string.isRequired,
			from: React.PropTypes.string.isRequired
		}).isRequired
	}).isRequired,
	dismissNote: React.PropTypes.func.isRequired,
	navigator: React.PropTypes.object.isRequired
};
<commit_msg>Add badges to notification center avatars<commit_after>import React from "react-native";
import Icon from "./icon";
import AvatarController from "../controllers/avatar-controller";
import TouchFeedback from "./touch-feedback";
import routes from "../utils/routes";
import timeUtils from "../../lib/time-utils";

const {
	StyleSheet,
	View,
	Text,
	TouchableHighlight,
	PixelRatio
} = React;

const styles = StyleSheet.create({
	item: {
		backgroundColor: "#fff",
		borderColor: "rgba(0, 0, 0, .08)",
		borderBottomWidth: 1 / PixelRatio.get()
	},
	note: {
		flexDirection: "row"
	},
	avatarContainer: {
		marginHorizontal: 16,
		marginVertical: 12
	},
	avatar: {
		height: 36,
		width: 36,
		borderRadius: 18,
		backgroundColor: "rgba(0, 0, 0, .16)"
	},
	image: {
		flex: 1,
		resizeMode: "cover",
		borderRadius: 18
	},
	content: {
		flex: 1,
		marginVertical: 8
	},
	title: {
		lineHeight: 21,
		color: "#999"
	},
	summary: {
		lineHeight: 18,
		fontSize: 12,
		color: "#999"
	},
	strong: {
		color: "#555"
	},
	timestampContainer: {
		flexDirection: "row"
	},
	timestamp: {
		fontSize: 11,
		marginVertical: 2,
		color: "#aaa",
		marginLeft: 4,
		paddingHorizontal: 4
	},
	icon: {
		fontSize: 12,
		color: "#000",
		marginVertical: 4,
		opacity: 0.3
	},
	close: {
		paddingVertical: 12,
		paddingHorizontal: 16
	},
	badge: {
		position: "absolute",
		alignItems: "center",
		bottom: -2,
		right: -2,
		height: 17,
		width: 17,
		borderRadius: 9,
		borderColor: "#fff",
		borderWidth: 2
	},
	badgeIcon: {
		marginVertical: 1,
		textAlign: "center",
		fontSize: 10,
		color: "#fff"
	}
});

export default class NotificationCenterItem extends React.Component {
	_extractPart(note, index) {
		return typeof note.group === "string" ? note.group.split("/")[index] : null;
	}

	_getThread(note) {
		const thread = this._extractPart(note, 1);

		return (thread === "all" || !thread) ? null : thread;
	}

	_getRoom(note) {
		return this._extractPart(note, 0);
	}

	_getSummary(note) {
		const max = 3;

		const { noteData, noteType, count } = note;

		const room = this._getRoom(this.props.note);

		const summary = [];

		switch (noteType) {
		case "mention":
			if (count > max) {
				summary.push(<Text key={1} style={styles.strong}>{count}</Text>, " new mentions in");
			} else {
				summary.push(<Text key={1} style={styles.strong}>{noteData.from}</Text>, " mentioned you in");
			}

			if (noteData.title) {
				summary.push(" ", <Text key={2} style={styles.strong}>{noteData.title}</Text>);
			}

			summary.push(" - ", <Text key={3} style={styles.strong}>{room}</Text>);

			break;
		case "reply":
			if (count > max) {
				summary.push(<Text key={1} style={styles.strong}>{count}</Text>, " new replies");
			} else {
				summary.push(<Text key={1} style={styles.strong}>{noteData.from}</Text>, " replied");
			}

			if (noteData.title) {
				summary.push(" to ", <Text key={2} style={styles.strong}>{noteData.title}</Text>);
			}

			summary.push(" in ", <Text key={3} style={styles.strong}>{room}</Text>);

			break;
		case "thread":
			if (count > max) {
				summary.push(<Text key={1} style={styles.strong}>{count}</Text>, " new discussions");
			} else {
				summary.push(<Text key={1} style={styles.strong}>{noteData.from}</Text>, " started a discussion");

				if (noteData.title) {
					summary.push(" on ", <Text key={2} style={styles.strong}>{noteData.title}</Text>);
				}
			}

			summary.push(" in ", <Text key={3} style={styles.strong}>{room}</Text>);

			break;
		default:
			if (count > max) {
				summary.push(<Text key={1} style={styles.strong}>{count}</Text>, " new notifications");
			} else {
				summary.push("New notification from ", <Text key={1} style={styles.strong}>{noteData.from}</Text>);
			}

			summary.push(" in ", <Text key={2} style={styles.strong}>{room}</Text>);
		}

		return summary;
	}

	_getIconColor() {
		const { note } = this.props;

		switch (note.noteType) {
		case "mention":
			return "#ff5722";
		case "reply":
			return "#2196F3";
		case "thread":
			return "#009688";
		default:
			return "#673ab7";
		}
	}

	_getIconName() {
		const { note } = this.props;

		switch (note.noteType) {
		case "mention":
			return "person";
		case "reply":
			return "reply";
		case "thread":
			return "create";
		default:
			return "notifications";
		}
	}

	_onPress() {
		const { note, navigator } = this.props;

		const room = this._getRoom(note);
		const thread = this._getThread(note);

		switch (note.noteType) {
		case "mention":
		case "reply":
		case "thread":
			navigator.push(routes.chat({
				thread,
				room
			}));

			break;
		default:
			navigator.push(routes.room({ room }));
		}
	}

	_onDismiss() {
		this.props.dismissNote(this.props.note);
	}

	render() {
		const { note } = this.props;

		return (
			<View style={styles.item}>
				<TouchFeedback onPress={this._onPress.bind(this)}>
					<View style={styles.note}>
						<View style={styles.avatarContainer}>
							<View style={styles.avatar}>
								<AvatarController
									size={36}
									nick={note.noteData.from}
									style={styles.image}
								/>
							</View>
							<View style={[ styles.badge, { backgroundColor: this._getIconColor() } ]}>
								<Icon name={this._getIconName()} style={styles.badgeIcon} />
							</View>
						</View>
						<View style={styles.content}>
							<View>
								<Text numberOfLines={5} style={styles.title} >{this._getSummary(note)}</Text>
							</View>
							<View>
								<Text numberOfLines={1} style={styles.summary} >{note.noteData.text}</Text>
							</View>
							<View style={styles.timestampContainer}>
								<Icon name="access-time" style={styles.icon} />
								<Text style={styles.timestamp}>{timeUtils.long(note.time)}</Text>
							</View>
						</View>
						<TouchableHighlight underlayColor="rgba(0, 0, 0, .08)" onPress={this._onDismiss.bind(this)}>
							<View style={styles.close}>
								<Icon name="close" style={styles.icon} />
							</View>
						</TouchableHighlight>
					</View>
				</TouchFeedback>
			</View>
		);
	}
}

NotificationCenterItem.propTypes = {
	note: React.PropTypes.shape({
		count: React.PropTypes.number,
		group: React.PropTypes.string.isRequired,
		noteType: React.PropTypes.string.isRequired,
		noteData: React.PropTypes.shape({
			title: React.PropTypes.string,
			text: React.PropTypes.string.isRequired,
			from: React.PropTypes.string.isRequired
		}).isRequired
	}).isRequired,
	dismissNote: React.PropTypes.func.isRequired,
	navigator: React.PropTypes.object.isRequired
};
<|endoftext|>


<commit_before>export default class Alert {
    constructor(ngToast, $filter) {
        'ngInject';

        // ngToast provider
        this._ngToast = ngToast;
        // Filters
        this._$filter = $filter;
    }

    /**
     * Error alerts
     */
    missingFormData() {
        this._ngToast.create({
            className: 'danger',
            content: this._$filter('translate')('ALERT_MISSING_FORM_DATA')
        });
    }

    errorWalletDownload() {
        this._ngToast.create({
            className: 'danger',
            content: this._$filter('translate')('ALERT_ERROR_WALLET_DOWNLOAD')
        });
    }

    passwordsNotMatching() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_PASSWORDS_NOT_MATCHING'),
            className: 'danger'
        });
    }

    invalidKeyForAddress() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_INVALID_KEY_FOR_ADDR'),
            className: 'danger'
        });
    }

    noWalletLoaded() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_NO_WALLET_LOADED'),
            className: 'danger'
        });
    }

    walletNameExists() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_WALLET_NAME_EXISTS'),
            className: 'danger'
        });
    }

    invalidWalletFile() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_INVALID_WALLET_FILE'),
            className: 'danger'
        });
    }

    noNodeSet() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_NO_NODE_SET'),
            className: 'danger'
        });
    }

    invalidCustomNode() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_INVALID_CUSTOM_NODE'),
            className: 'danger'
        });
    }

    invalidWebsocketPort() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_INVALID_WEBSOCKET_PORT'),
            className: 'danger'
        });
    }

    websocketError(message) {
        this._ngToast.create({
            content: message,
            className: 'danger'
        });
    }

    mijinDisabled() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_MIJIN_DISABLED'),
            className: 'danger'
        });
    }

    getNamespacesByIdError(message) {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_GET_NS_BY_ID_ERROR') + message,
            className: 'danger'
        });
    }

    getAccountDataError(message) {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_GET_ACCOUNT_DATA_ERROR') + message,
            className: 'danger'
        });
    }

    invalidAddressForNetwork(address, network) {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_ERROR_OCCURRED') + address + this._$filter('translate')('ALERT_INVALID_ADDR_FOR_NETWORK') + '(' + network + ') !',
            className: 'danger'
        });
    }

    invalidPassword() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_INVALID_PASSWORD'),
            className: 'danger'
        });
    }

    transactionError(message) {
        this._ngToast.create({
            content: message,
            className: 'danger'
        });
    }

    cosignatoryAlreadyPresentInList(){
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_COSIG_ALREADY_IN_LIST'),
            className: 'danger'
        });
    }

    cosignatoryhasNoPubKey(){
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_COSIGNATORY_HAS_NO_PUBLIC'),
            className: 'danger'
        });
    }

    multisighasNoPubKey(){
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_MULTISIG_HAS_NO_PUBLIC'),
            className: 'danger'
        });
    }

    cosignatoryCannotBeMultisig(){
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_COSIG_CANNOT_BE_MULTISIG'),
            className: 'danger'
        });
    }

    noNamespaceOwned(){
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_NO_NS_OWNED'),
            className: 'danger'
        });
    }

    unlockedInfoError(){
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_UNLOCKED_INFO_ERROR'),
            className: 'danger'
        });
    }

    lockError(message) {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_LOCK_ERROR') + message,
            className: 'danger'
        });
    }

    unlockError(message) {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_UNLOCK_ERROR') + message,
            className: 'danger'
        });
    }

    supernodesError() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_SUPERNODES_ERROR'),
            className: 'danger'
        });
    }

    invalidNtyFile() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_INVALID_NTY_FILE'),
            className: 'danger'
        });
    }

    createWalletFailed(err) {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_CREATE_WALLET_FAILED') + err,
            className: 'danger'
        });
    }

    derivationFromSeedFailed(err) {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_DERIVATION_FROM_SEED_FAILED') + err,
            className: 'danger'
        });
    }

    bip32GenerationFailed(err) {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_BIP32_GENERATION_FAILED') + err,
            className: 'danger'
        });
    }

    noWalletData() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_NO_WALLET_DATA'),
            className: 'danger'
        });
    }

    cantLoginWithoutWallet() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_CANNOT_LOGIN_WITHOU_WALLET'),
            className: 'danger'
        });
    }

    noWalletToSet() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_NO_WALLET_TO_SET'),
            className: 'danger'
        });
    }

    invalidWalletIndex() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_INVALID_WALLET_INDEX'),
            className: 'danger'
        });
    }

    noCurrentWallet() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_NO_CURRENT_WALLET'),
            className: 'danger'
        });
    }

    alreadyMultisig() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_ALREADY_MULTISIG'),
            className: 'danger'
        });
    }

    invalidModificationArray() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_INVALID_MODIFICATION_ARRAY'),
            className: 'danger'
        });
    }

    errorGetMarketInfo() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_GET_MARKET_INFO_ERROR'),
            className: 'danger'
        });
    }

    multisigCannotBeCosignatory() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_MULTISIG_CANNOT_BE_COSIG'),
            className: 'danger'
        });
    }

    purgeCancelled() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_PURGE_CANCELLED'),
            className: 'danger'
        });
    }

    mainnetDisabled() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_MAINNET_DISABLED'),
            className: 'danger'
        });
    }

    emptyDecodedMessage() {
       this._ngToast.create({
            content: this._$filter('translate')('ALERT_EMPTY_DECODED_MSG'),
            className: 'danger'
        });
    }

    invalidNamespaceName() {
       this._ngToast.create({
            content: this._$filter('translate')('ALERT_INVALID_NS_NAME'),
            className: 'danger'
        });
    }

    invalidMosaicName() {
       this._ngToast.create({
            content: this._$filter('translate')('ALERT_INVALID_MOSAIC_NAME'),
            className: 'danger'
        });
    }

    invalidMosaicDescription() {
       this._ngToast.create({
            content: this._$filter('translate')('ALERT_MOSAIC_DESCRIPTION'),
            className: 'danger'
        });
    }

    errorFetchingIncomingTxes() {
         this._ngToast.create({
            content: this._$filter('translate')('ALERT_GET_INCOMING_TXES_ERROR'),
            className: 'danger'
        });
    }

    /**
     * Success alerts
     */
    createWalletSuccess() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_CREATE_WALLET_SUCCESS'),
            className: 'success'
        });
    }

    successPurge() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_SUCCESS_PURGE'),
            className: 'success'
        });
    }

    successLogout() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_SUCCESS_LOGOUT'),
            className: 'success'
        });
    }

    loadWalletSuccess() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_LOAD_WALLET_SUCCESS'),
            className: 'success'
        });
    }

    transactionSuccess() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_TRANSACTION_SUCCESS'),
            className: 'success'
        });
    }

    generateNewAccountSuccess() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_GENERATE_ACCOUNT_SUCCESS'),
            className: 'success'
        });
    }

    upgradeSuccess() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_UPGRADE_SUCCESS'),
            className: 'success'
        });
    }

    transactionSignatureSuccess() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_SIGNATURE_SUCCESS'),
            className: 'success'
        });
    }

    ntyFileSuccess() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_NTY_FILE_SUCCESS'),
            className: 'success'
        });
    }

    /**
     * Transaction notifications
     */

    incomingTransaction(signer, network) {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_INCOMING_TX_FROM') + this._$filter('fmtPubToAddress')(signer, network),
            className: 'success'
        });
    }

}<commit_msg>More alerts<commit_after>export default class Alert {
    constructor(ngToast, $filter) {
        'ngInject';

        // ngToast provider
        this._ngToast = ngToast;
        // Filters
        this._$filter = $filter;
    }

    /***
     * Error alerts
     */
    missingFormData() {
        this._ngToast.create({
            className: 'danger',
            content: this._$filter('translate')('ALERT_MISSING_FORM_DATA')
        });
    }

    errorWalletDownload() {
        this._ngToast.create({
            className: 'danger',
            content: this._$filter('translate')('ALERT_ERROR_WALLET_DOWNLOAD')
        });
    }

    passwordsNotMatching() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_PASSWORDS_NOT_MATCHING'),
            className: 'danger'
        });
    }

    invalidKeyForAddress() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_INVALID_KEY_FOR_ADDR'),
            className: 'danger'
        });
    }

    noWalletLoaded() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_NO_WALLET_LOADED'),
            className: 'danger'
        });
    }

    walletNameExists() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_WALLET_NAME_EXISTS'),
            className: 'danger'
        });
    }

    invalidWalletFile() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_INVALID_WALLET_FILE'),
            className: 'danger'
        });
    }

    noNodeSet() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_NO_NODE_SET'),
            className: 'danger'
        });
    }

    invalidCustomNode() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_INVALID_CUSTOM_NODE'),
            className: 'danger'
        });
    }

    invalidWebsocketPort() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_INVALID_WEBSOCKET_PORT'),
            className: 'danger'
        });
    }

    websocketError(message) {
        this._ngToast.create({
            content: message,
            className: 'danger'
        });
    }

    mijinDisabled() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_MIJIN_DISABLED'),
            className: 'danger'
        });
    }

    getNamespacesByIdError(message) {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_GET_NS_BY_ID_ERROR') + message,
            className: 'danger'
        });
    }

    getAccountDataError(message) {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_GET_ACCOUNT_DATA_ERROR') + message,
            className: 'danger'
        });
    }

    invalidAddressForNetwork(address, network) {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_ERROR_OCCURRED') + address + this._$filter('translate')('ALERT_INVALID_ADDR_FOR_NETWORK') + '(' + network + ') !',
            className: 'danger'
        });
    }

    invalidPassword() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_INVALID_PASSWORD'),
            className: 'danger'
        });
    }

    transactionError(message) {
        this._ngToast.create({
            content: message,
            className: 'danger'
        });
    }

    cosignatoryAlreadyPresentInList(){
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_COSIG_ALREADY_IN_LIST'),
            className: 'danger'
        });
    }

    cosignatoryhasNoPubKey(){
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_COSIGNATORY_HAS_NO_PUBLIC'),
            className: 'danger'
        });
    }

    multisighasNoPubKey(){
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_MULTISIG_HAS_NO_PUBLIC'),
            className: 'danger'
        });
    }

    cosignatoryCannotBeMultisig(){
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_COSIG_CANNOT_BE_MULTISIG'),
            className: 'danger'
        });
    }

    noNamespaceOwned(){
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_NO_NS_OWNED'),
            className: 'danger'
        });
    }

    unlockedInfoError(){
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_UNLOCKED_INFO_ERROR'),
            className: 'danger'
        });
    }

    lockError(message) {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_LOCK_ERROR') + message,
            className: 'danger'
        });
    }

    unlockError(message) {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_UNLOCK_ERROR') + message,
            className: 'danger'
        });
    }

    supernodesError() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_SUPERNODES_ERROR'),
            className: 'danger'
        });
    }

    invalidNtyFile() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_INVALID_NTY_FILE'),
            className: 'danger'
        });
    }

    createWalletFailed(err) {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_CREATE_WALLET_FAILED') + err,
            className: 'danger'
        });
    }

    derivationFromSeedFailed(err) {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_DERIVATION_FROM_SEED_FAILED') + err,
            className: 'danger'
        });
    }

    bip32GenerationFailed(err) {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_BIP32_GENERATION_FAILED') + err,
            className: 'danger'
        });
    }

    noWalletData() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_NO_WALLET_DATA'),
            className: 'danger'
        });
    }

    cantLoginWithoutWallet() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_CANNOT_LOGIN_WITHOU_WALLET'),
            className: 'danger'
        });
    }

    noWalletToSet() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_NO_WALLET_TO_SET'),
            className: 'danger'
        });
    }

    invalidWalletIndex() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_INVALID_WALLET_INDEX'),
            className: 'danger'
        });
    }

    noCurrentWallet() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_NO_CURRENT_WALLET'),
            className: 'danger'
        });
    }

    alreadyMultisig() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_ALREADY_MULTISIG'),
            className: 'danger'
        });
    }

    invalidModificationArray() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_INVALID_MODIFICATION_ARRAY'),
            className: 'danger'
        });
    }

    errorGetMarketInfo() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_GET_MARKET_INFO_ERROR'),
            className: 'danger'
        });
    }

    multisigCannotBeCosignatory() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_MULTISIG_CANNOT_BE_COSIG'),
            className: 'danger'
        });
    }

    purgeCancelled() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_PURGE_CANCELLED'),
            className: 'danger'
        });
    }

    mainnetDisabled() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_MAINNET_DISABLED'),
            className: 'danger'
        });
    }

    emptyDecodedMessage() {
       this._ngToast.create({
            content: this._$filter('translate')('ALERT_EMPTY_DECODED_MSG'),
            className: 'danger'
        });
    }

    invalidNamespaceName() {
       this._ngToast.create({
            content: this._$filter('translate')('ALERT_INVALID_NS_NAME'),
            className: 'danger'
        });
    }

    invalidMosaicName() {
       this._ngToast.create({
            content: this._$filter('translate')('ALERT_INVALID_MOSAIC_NAME'),
            className: 'danger'
        });
    }

    invalidMosaicDescription() {
       this._ngToast.create({
            content: this._$filter('translate')('ALERT_MOSAIC_DESCRIPTION'),
            className: 'danger'
        });
    }

    errorFetchingIncomingTxes(message) {
         this._ngToast.create({
            content: this._$filter('translate')('ALERT_GET_INCOMING_TXES_ERROR') + message,
            className: 'danger'
        });
    }

    connectionError() {
         this._ngToast.create({
            content: this._$filter("translate")("GENERAL_CONNECTION_ERROR"),
            className: 'danger'
        });
    }

    errorGetMosaicsDefintions(message) {
        this._ngToast.create({
            content: this._$filter("translate")("ALERT_GET_MOSAICS_DEFINITIONS_ERROR") + message,
            className: 'danger'
        });
    }

    errorGetSubNamespaces(message) {
        this._ngToast.create({
            content: this._$filter("translate")("ALERT_GET_SUB_NS_ERROR") + message,
            className: 'danger'
        });
    }

    errorGetMosaics(message) {
        this._ngToast.create({
            content: this._$filter("translate")("ALERT_GET_MOSAICS_ERROR") + message,
            className: 'danger'
        });
    }

    errorGetTransactions(message) {
        this._ngToast.create({
            content: this._$filter("translate")("ALERT_GET_TRANSACTIONS_ERROR") + message,
            className: 'danger'
        });
    }

    /***
     * Success alerts
     */
    createWalletSuccess() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_CREATE_WALLET_SUCCESS'),
            className: 'success'
        });
    }

    successPurge() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_SUCCESS_PURGE'),
            className: 'success'
        });
    }

    successLogout() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_SUCCESS_LOGOUT'),
            className: 'success'
        });
    }

    loadWalletSuccess() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_LOAD_WALLET_SUCCESS'),
            className: 'success'
        });
    }

    transactionSuccess() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_TRANSACTION_SUCCESS'),
            className: 'success'
        });
    }

    generateNewAccountSuccess() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_GENERATE_ACCOUNT_SUCCESS'),
            className: 'success'
        });
    }

    upgradeSuccess() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_UPGRADE_SUCCESS'),
            className: 'success'
        });
    }

    transactionSignatureSuccess() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_SIGNATURE_SUCCESS'),
            className: 'success'
        });
    }

    ntyFileSuccess() {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_NTY_FILE_SUCCESS'),
            className: 'success'
        });
    }

    /***
     * Transaction notifications
     */

    incomingTransaction(signer, network) {
        this._ngToast.create({
            content: this._$filter('translate')('ALERT_INCOMING_TX_FROM') + this._$filter('fmtPubToAddress')(signer, network),
            className: 'success'
        });
    }

}<|endoftext|>


<commit_before><commit_msg>Add invisible wall that gets texture from textures/wall.jpg<commit_after><|endoftext|>


<commit_before>/*global Markdown:true, hljs:true */

/**
  Contains methods to help us with markdown formatting.

  @class Markdown
  @namespace Discourse
  @module Discourse
**/
var _validClasses = {},
    _validIframes = [],
    _validTags = {};

function validateAttribute(tagName, attribName, value) {
  var tag = _validTags[tagName];

  // Handle classes
  if (attribName === "class") {
    if (_validClasses[value]) { return value; }

    if (tag) {
      var classes = tag['class'];
      if (classes && (classes.indexOf(value) !== -1 || classes.indexOf('*') !== -1)) {
        return value;
      }
    }
  } else if (attribName.indexOf('data-') === 0) {
    // data-* attributes
    if (tag) {
      var allowed = tag[attribName] || tag['data-*'];
      if (allowed === value || allowed.indexOf('*') !== -1) { return value; }
    }
  }

  if (tag) {
    var attrs = tag[attribName];
    if (attrs && (attrs.indexOf(value) !== -1 ||
                  attrs.indexOf('*') !== -1) ||
                  _.any(attrs,function(r){return (r instanceof RegExp) && value.search(r) >= 0;})
        ) { return value; }
  }
}

Discourse.Markdown = {

  /**
    Whitelist class for only a certain tag

    @param {String} tagName to whitelist
    @param {String} attribName to whitelist
    @param {String} value to whitelist
  **/
  whiteListTag: function(tagName, attribName, value) {
    _validTags[tagName] = _validTags[tagName] || {};
    _validTags[tagName][attribName] = _validTags[tagName][attribName] || [];
    _validTags[tagName][attribName].push(value || '*');
  },

  /**
    Whitelists more classes for sanitization.

    @param {...String} var_args Classes to whitelist
    @method whiteListClass
  **/
  whiteListClass: function() {
    var args = Array.prototype.slice.call(arguments);
    args.forEach(function (a) { _validClasses[a] = true; });
  },

  /**
    Whitelists iframes for sanitization

    @method whiteListIframe
    @param {Regexp} regexp The regexp to whitelist.
  **/
  whiteListIframe: function(regexp) {
    _validIframes.push(regexp);
  },

  /**
    Convert a raw string to a cooked markdown string.

    @method cook
    @param {String} raw the raw string we want to apply markdown to
    @param {Object} opts the options for the rendering
    @return {String} the cooked markdown string
  **/
  cook: function(raw, opts) {
    if (!opts) opts = {};

    // Make sure we've got a string
    if (!raw || raw.length === 0) return "";

    return this.markdownConverter(opts).makeHtml(raw);
  },

  /**
    Creates a new pagedown markdown editor, supplying i18n translations.

    @method createEditor
    @param {Object} converterOptions custom options for our markdown converter
    @return {Markdown.Editor} the editor instance
  **/
  createEditor: function(converterOptions) {
    if (!converterOptions) converterOptions = {};

    // By default we always sanitize content in the editor
    converterOptions.sanitize = true;

    var markdownConverter = Discourse.Markdown.markdownConverter(converterOptions);

    var editorOptions = {
      strings: {
        bold: I18n.t("composer.bold_title") + "  Ctrl+B",
        boldexample: I18n.t("composer.bold_text"),

        italic: I18n.t("composer.italic_title") + "  Ctrl+I",
        italicexample: I18n.t("composer.italic_text"),

        link: I18n.t("composer.link_title") + "  Ctrl+L",
        linkdescription: I18n.t("composer.link_description"),
        linkdialog: "
" + I18n.t("composer.link_dialog_title") + "

http://example.com/ \"" +
            I18n.t("composer.link_optional_text") + "\"
",

        quote: I18n.t("composer.quote_title") + "
 Ctrl+Q",
        quoteexample: I18n.t("composer.quote_text"),

        code: I18n.t("composer.code_title") + "
 Ctrl+K",
        codeexample: I18n.t("composer.code_text"),

        image: I18n.t("composer.upload_title") + " - Ctrl+G",
        imagedescription: I18n.t("composer.upload_description"),

        olist: I18n.t("composer.olist_title") + "
 Ctrl+O",
        ulist: I18n.t("composer.ulist_title") + "
 Ctrl+U",
        litem: I18n.t("composer.list_item"),

        heading: I18n.t("composer.heading_title") + "
/
 Ctrl+H",
        headingexample: I18n.t("composer.heading_text"),

        hr: I18n.t("composer.hr_title") + "
 Ctrl+R",

        undo: I18n.t("composer.undo_title") + " - Ctrl+Z",
        redo: I18n.t("composer.redo_title") + " - Ctrl+Y",
        redomac: I18n.t("composer.redo_title") + " - Ctrl+Shift+Z",

        help: I18n.t("composer.help")
      }
    };

    return new Markdown.Editor(markdownConverter, undefined, editorOptions);
  },

  /**
    Checks to see if a URL is allowed in the cooked content

    @method urlAllowed
    @param {String} uri Url to check
    @param {Number} effect ignored
    @param {Number} ltype ignored
    @param {Object} hints an object with hints, used to check if this url is from an iframe
    @return {String} url to insert in the cooked content
  **/
  urlAllowed: function (uri, effect, ltype, hints) {
    var url = typeof(uri) === "string" ? uri : uri.toString();

    // whitelist some iframe only
    if (hints && hints.XML_TAG === "iframe" && hints.XML_ATTR === "src") {
      for (var i = 0, length = _validIframes.length; i < length; i++) {
        if(_validIframes[i].test(url)) { return url; }
      }
      return;
    }

    // absolute urls
    if(/^(https?:)?\/\/[\w\.\-]+/i.test(url)) { return url; }
    // relative urls
    if(/^\/[\w\.\-]+/i.test(url)) { return url; }
    // anchors
    if(/^#[\w\.\-]+/i.test(url)) { return url; }
    // mailtos
    if(/^mailto:[\w\.\-@]+/i.test(url)) { return url; }
  },

  /**
    Sanitize text using the sanitizer

    @method sanitize
    @param {String} text The text to sanitize
    @return {String} text The sanitized text
  **/
  sanitize: function(text) {
    if (!window.html_sanitize || !text) return "";

    // Allow things like <3 and <_<
    text = text.replace(/<([^A-Za-z\/\!]|$)/g, "<$1");

    return window.html_sanitize(text, Discourse.Markdown.urlAllowed, validateAttribute);
  },

  /**
    Creates a Markdown.Converter that we we can use for formatting

    @method markdownConverter
    @param {Object} opts the converting options
  **/
  markdownConverter: function(opts) {
    if (!opts) opts = {};

    return {
      makeHtml: function(text) {
        text = Discourse.Dialect.cook(text, opts);
        return !text ? "" : text;
      }
    };
  }

};

RSVP.EventTarget.mixin(Discourse.Markdown);

Discourse.Markdown.whiteListTag('a', 'class', 'attachment');
Discourse.Markdown.whiteListTag('a', 'target', '_blank');
Discourse.Markdown.whiteListTag('a', 'class', 'onebox');
Discourse.Markdown.whiteListTag('a', 'class', 'mention');

Discourse.Markdown.whiteListTag('a', 'data-bbcode');

Discourse.Markdown.whiteListTag('div', 'class', 'title');
Discourse.Markdown.whiteListTag('div', 'class', 'quote-controls');

// explicitly whitelist classes we need allowed through for
// syntax highlighting, grabbed from highlight.js
hljs.listLanguages().forEach(function (language) {
  Discourse.Markdown.whiteListTag('code', 'class', language);
});
Discourse.Markdown.whiteListTag('code', 'class', 'text');
Discourse.Markdown.whiteListTag('code', 'class', 'lang-auto');

Discourse.Markdown.whiteListTag('span', 'class', 'mention');
Discourse.Markdown.whiteListTag('span', 'class', 'spoiler');
Discourse.Markdown.whiteListTag('div', 'class', 'spoiler');
Discourse.Markdown.whiteListTag('aside', 'class', 'quote');
Discourse.Markdown.whiteListTag('aside', 'data-*');

Discourse.Markdown.whiteListTag('span', 'bbcode-b');
Discourse.Markdown.whiteListTag('span', 'bbcode-i');
Discourse.Markdown.whiteListTag('span', 'bbcode-u');
Discourse.Markdown.whiteListTag('span', 'bbcode-s');

Discourse.Markdown.whiteListIframe(/^(https?:)?\/\/www\.google\.com\/maps\/embed\?.+/i);
<commit_msg>BUGFIX: exception validating 'data-' attributes<commit_after>/*global Markdown:true, hljs:true */

/**
  Contains methods to help us with markdown formatting.

  @class Markdown
  @namespace Discourse
  @module Discourse
**/
var _validClasses = {},
    _validIframes = [],
    _validTags = {};

function validateAttribute(tagName, attribName, value) {
  var tag = _validTags[tagName];

  // Handle classes
  if (attribName === "class") {
    if (_validClasses[value]) { return value; }

    if (tag) {
      var classes = tag['class'];
      if (classes && (classes.indexOf(value) !== -1 || classes.indexOf('*') !== -1)) {
        return value;
      }
    }
  } else if (attribName.indexOf('data-') === 0) {
    // data-* attributes
    if (tag) {
      var allowed = tag[attribName] || tag['data-*'];
      if (allowed && (allowed === value || allowed.indexOf('*') !== -1)) { return value; }
    }
  }

  if (tag) {
    var attrs = tag[attribName];
    if (attrs && (attrs.indexOf(value) !== -1 ||
                  attrs.indexOf('*') !== -1) ||
                  _.any(attrs,function(r){return (r instanceof RegExp) && value.search(r) >= 0;})
        ) { return value; }
  }
}

Discourse.Markdown = {

  /**
    Whitelist class for only a certain tag

    @param {String} tagName to whitelist
    @param {String} attribName to whitelist
    @param {String} value to whitelist
  **/
  whiteListTag: function(tagName, attribName, value) {
    _validTags[tagName] = _validTags[tagName] || {};
    _validTags[tagName][attribName] = _validTags[tagName][attribName] || [];
    _validTags[tagName][attribName].push(value || '*');
  },

  /**
    Whitelists more classes for sanitization.

    @param {...String} var_args Classes to whitelist
    @method whiteListClass
  **/
  whiteListClass: function() {
    var args = Array.prototype.slice.call(arguments);
    args.forEach(function (a) { _validClasses[a] = true; });
  },

  /**
    Whitelists iframes for sanitization

    @method whiteListIframe
    @param {Regexp} regexp The regexp to whitelist.
  **/
  whiteListIframe: function(regexp) {
    _validIframes.push(regexp);
  },

  /**
    Convert a raw string to a cooked markdown string.

    @method cook
    @param {String} raw the raw string we want to apply markdown to
    @param {Object} opts the options for the rendering
    @return {String} the cooked markdown string
  **/
  cook: function(raw, opts) {
    if (!opts) opts = {};

    // Make sure we've got a string
    if (!raw || raw.length === 0) return "";

    return this.markdownConverter(opts).makeHtml(raw);
  },

  /**
    Creates a new pagedown markdown editor, supplying i18n translations.

    @method createEditor
    @param {Object} converterOptions custom options for our markdown converter
    @return {Markdown.Editor} the editor instance
  **/
  createEditor: function(converterOptions) {
    if (!converterOptions) converterOptions = {};

    // By default we always sanitize content in the editor
    converterOptions.sanitize = true;

    var markdownConverter = Discourse.Markdown.markdownConverter(converterOptions);

    var editorOptions = {
      strings: {
        bold: I18n.t("composer.bold_title") + "  Ctrl+B",
        boldexample: I18n.t("composer.bold_text"),

        italic: I18n.t("composer.italic_title") + "  Ctrl+I",
        italicexample: I18n.t("composer.italic_text"),

        link: I18n.t("composer.link_title") + "  Ctrl+L",
        linkdescription: I18n.t("composer.link_description"),
        linkdialog: "
" + I18n.t("composer.link_dialog_title") + "

http://example.com/ \"" +
            I18n.t("composer.link_optional_text") + "\"
",

        quote: I18n.t("composer.quote_title") + "
 Ctrl+Q",
        quoteexample: I18n.t("composer.quote_text"),

        code: I18n.t("composer.code_title") + "
 Ctrl+K",
        codeexample: I18n.t("composer.code_text"),

        image: I18n.t("composer.upload_title") + " - Ctrl+G",
        imagedescription: I18n.t("composer.upload_description"),

        olist: I18n.t("composer.olist_title") + "
 Ctrl+O",
        ulist: I18n.t("composer.ulist_title") + "
 Ctrl+U",
        litem: I18n.t("composer.list_item"),

        heading: I18n.t("composer.heading_title") + "
/
 Ctrl+H",
        headingexample: I18n.t("composer.heading_text"),

        hr: I18n.t("composer.hr_title") + "
 Ctrl+R",

        undo: I18n.t("composer.undo_title") + " - Ctrl+Z",
        redo: I18n.t("composer.redo_title") + " - Ctrl+Y",
        redomac: I18n.t("composer.redo_title") + " - Ctrl+Shift+Z",

        help: I18n.t("composer.help")
      }
    };

    return new Markdown.Editor(markdownConverter, undefined, editorOptions);
  },

  /**
    Checks to see if a URL is allowed in the cooked content

    @method urlAllowed
    @param {String} uri Url to check
    @param {Number} effect ignored
    @param {Number} ltype ignored
    @param {Object} hints an object with hints, used to check if this url is from an iframe
    @return {String} url to insert in the cooked content
  **/
  urlAllowed: function (uri, effect, ltype, hints) {
    var url = typeof(uri) === "string" ? uri : uri.toString();

    // whitelist some iframe only
    if (hints && hints.XML_TAG === "iframe" && hints.XML_ATTR === "src") {
      for (var i = 0, length = _validIframes.length; i < length; i++) {
        if(_validIframes[i].test(url)) { return url; }
      }
      return;
    }

    // absolute urls
    if(/^(https?:)?\/\/[\w\.\-]+/i.test(url)) { return url; }
    // relative urls
    if(/^\/[\w\.\-]+/i.test(url)) { return url; }
    // anchors
    if(/^#[\w\.\-]+/i.test(url)) { return url; }
    // mailtos
    if(/^mailto:[\w\.\-@]+/i.test(url)) { return url; }
  },

  /**
    Sanitize text using the sanitizer

    @method sanitize
    @param {String} text The text to sanitize
    @return {String} text The sanitized text
  **/
  sanitize: function(text) {
    if (!window.html_sanitize || !text) return "";

    // Allow things like <3 and <_<
    text = text.replace(/<([^A-Za-z\/\!]|$)/g, "<$1");

    return window.html_sanitize(text, Discourse.Markdown.urlAllowed, validateAttribute);
  },

  /**
    Creates a Markdown.Converter that we we can use for formatting

    @method markdownConverter
    @param {Object} opts the converting options
  **/
  markdownConverter: function(opts) {
    if (!opts) opts = {};

    return {
      makeHtml: function(text) {
        text = Discourse.Dialect.cook(text, opts);
        return !text ? "" : text;
      }
    };
  }

};

RSVP.EventTarget.mixin(Discourse.Markdown);

Discourse.Markdown.whiteListTag('a', 'class', 'attachment');
Discourse.Markdown.whiteListTag('a', 'target', '_blank');
Discourse.Markdown.whiteListTag('a', 'class', 'onebox');
Discourse.Markdown.whiteListTag('a', 'class', 'mention');

Discourse.Markdown.whiteListTag('a', 'data-bbcode');

Discourse.Markdown.whiteListTag('div', 'class', 'title');
Discourse.Markdown.whiteListTag('div', 'class', 'quote-controls');

// explicitly whitelist classes we need allowed through for
// syntax highlighting, grabbed from highlight.js
hljs.listLanguages().forEach(function (language) {
  Discourse.Markdown.whiteListTag('code', 'class', language);
});
Discourse.Markdown.whiteListTag('code', 'class', 'text');
Discourse.Markdown.whiteListTag('code', 'class', 'lang-auto');

Discourse.Markdown.whiteListTag('span', 'class', 'mention');
Discourse.Markdown.whiteListTag('span', 'class', 'spoiler');
Discourse.Markdown.whiteListTag('div', 'class', 'spoiler');
Discourse.Markdown.whiteListTag('aside', 'class', 'quote');
Discourse.Markdown.whiteListTag('aside', 'data-*');

Discourse.Markdown.whiteListTag('span', 'bbcode-b');
Discourse.Markdown.whiteListTag('span', 'bbcode-i');
Discourse.Markdown.whiteListTag('span', 'bbcode-u');
Discourse.Markdown.whiteListTag('span', 'bbcode-s');

Discourse.Markdown.whiteListIframe(/^(https?:)?\/\/www\.google\.com\/maps\/embed\?.+/i);
<|endoftext|>


<commit_before>/**
 * @author mr.doob / http://mrdoob.com/
 * @author kile / http://kile.stravaganza.org/
 * @author philogb / http://blog.thejit.org/
 */

THREE.Vector3 = function ( x, y, z ) {

	this.x = x || 0;
	this.y = y || 0;
	this.z = z || 0;

};

THREE.Vector3.prototype = {

	set: function ( x, y, z ) {

		this.x = x;
		this.y = y;
		this.z = z;

		return this;

	},

	copy: function ( v ) {

		this.x = v.x;
		this.y = v.y;
		this.z = v.z;

		return this;

	},

	add: function ( a, b ) {

		this.x = a.x + b.x;
		this.y = a.y + b.y;
		this.z = a.z + b.z;

		return this;

	},

	addSelf: function ( v ) {

		this.x += v.x;
		this.y += v.y;
		this.z += v.z;

		return this;

	},

	addScalar: function ( s ) {

		this.x += s;
		this.y += s;
		this.z += s;

		return this;

	},

	sub: function( a, b ) {

		this.x = a.x - b.x;
		this.y = a.y - b.y;
		this.z = a.z - b.z;

		return this;

	},

	subSelf: function ( v ) {

		this.x -= v.x;
		this.y -= v.y;
		this.z -= v.z;

		return this;

	},

	cross: function ( a, b ) {

		this.x = a.y * b.z - a.z * b.y;
		this.y = a.z * b.x - a.x * b.z;
		this.z = a.x * b.y - a.y * b.x;

		return this;

	},

	crossSelf: function ( v ) {

		var tx = this.x, ty = this.y, tz = this.z;

		this.x = ty * v.z - tz * v.y;
		this.y = tz * v.x - tx * v.z;
		this.z = tx * v.y - ty * v.x;

		return this;

	},

	multiply: function ( a, b ) {

		this.x = a.x * b.x;
		this.y = a.y * b.y;
		this.z = a.z * b.z;

		return this;

	},

	multiplySelf: function ( v ) {

		this.x *= v.x;
		this.y *= v.y;
		this.z *= v.z;

		return this;

	},

	multiplyScalar: function ( s ) {

		this.x *= s;
		this.y *= s;
		this.z *= s;

		return this;

	},

	divideScalar: function ( s ) {

		this.x /= s;
		this.y /= s;
		this.z /= s;

		return this;

	},

	dot: function ( v ) {

		return this.x * v.x + this.y * v.y + this.z * v.z;

	},

	distanceTo: function ( v ) {

		var dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z;
		return Math.sqrt( dx * dx + dy * dy + dz * dz );

	},

	distanceToSquared: function ( v ) {

		var dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z;
		return dx * dx + dy * dy + dz * dz;

	},

	length: function () {

		return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z );

	},

	lengthSq: function () {

		return this.x * this.x + this.y * this.y + this.z * this.z;

	},

	negate: function () {

		this.x = - this.x;
		this.y = - this.y;
		this.z = - this.z;

		return this;

	},

	normalize: function () {

		var length = Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z );

		length > 0 ? this.multiplyScalar( 1 / length ) : this.set( 0, 0, 0 );

		return this;

	},

	setLength: function( len ) {

		return this.normalize().multiplyScalar( len );

	},

	isZero: function () {

		var almostZero = 0.0001;
		return ( Math.abs( this.x ) < almostZero ) && ( Math.abs( this.y ) < almostZero ) && ( Math.abs( this.z ) < almostZero );

	},

	clone: function () {

		return new THREE.Vector3( this.x, this.y, this.z );

	},

	toString: function () {

		return 'THREE.Vector3 ( ' + this.x + ', ' + this.y + ', ' + this.z + ' )';

	}

};
<commit_msg>Added divideSelf to Vector3.<commit_after>/**
 * @author mr.doob / http://mrdoob.com/
 * @author kile / http://kile.stravaganza.org/
 * @author philogb / http://blog.thejit.org/
 */

THREE.Vector3 = function ( x, y, z ) {

	this.x = x || 0;
	this.y = y || 0;
	this.z = z || 0;

};

THREE.Vector3.prototype = {

	set: function ( x, y, z ) {

		this.x = x;
		this.y = y;
		this.z = z;

		return this;

	},

	copy: function ( v ) {

		this.x = v.x;
		this.y = v.y;
		this.z = v.z;

		return this;

	},

	add: function ( a, b ) {

		this.x = a.x + b.x;
		this.y = a.y + b.y;
		this.z = a.z + b.z;

		return this;

	},

	addSelf: function ( v ) {

		this.x += v.x;
		this.y += v.y;
		this.z += v.z;

		return this;

	},

	addScalar: function ( s ) {

		this.x += s;
		this.y += s;
		this.z += s;

		return this;

	},

	sub: function( a, b ) {

		this.x = a.x - b.x;
		this.y = a.y - b.y;
		this.z = a.z - b.z;

		return this;

	},

	subSelf: function ( v ) {

		this.x -= v.x;
		this.y -= v.y;
		this.z -= v.z;

		return this;

	},

	cross: function ( a, b ) {

		this.x = a.y * b.z - a.z * b.y;
		this.y = a.z * b.x - a.x * b.z;
		this.z = a.x * b.y - a.y * b.x;

		return this;

	},

	crossSelf: function ( v ) {

		var tx = this.x, ty = this.y, tz = this.z;

		this.x = ty * v.z - tz * v.y;
		this.y = tz * v.x - tx * v.z;
		this.z = tx * v.y - ty * v.x;

		return this;

	},

	multiply: function ( a, b ) {

		this.x = a.x * b.x;
		this.y = a.y * b.y;
		this.z = a.z * b.z;

		return this;

	},

	multiplySelf: function ( v ) {

		this.x *= v.x;
		this.y *= v.y;
		this.z *= v.z;

		return this;

	},

	multiplyScalar: function ( s ) {

		this.x *= s;
		this.y *= s;
		this.z *= s;

		return this;

	},

	divideSelf: function ( v ) {

		this.x /= v.x;
		this.y /= v.y;
		this.z /= v.z;

		return this;

	},

	divideScalar: function ( s ) {

		this.x /= s;
		this.y /= s;
		this.z /= s;

		return this;

	},

	dot: function ( v ) {

		return this.x * v.x + this.y * v.y + this.z * v.z;

	},

	distanceTo: function ( v ) {

		var dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z;
		return Math.sqrt( dx * dx + dy * dy + dz * dz );

	},

	distanceToSquared: function ( v ) {

		var dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z;
		return dx * dx + dy * dy + dz * dz;

	},

	length: function () {

		return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z );

	},

	lengthSq: function () {

		return this.x * this.x + this.y * this.y + this.z * this.z;

	},

	negate: function () {

		this.x = - this.x;
		this.y = - this.y;
		this.z = - this.z;

		return this;

	},

	normalize: function () {

		var length = Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z );

		length > 0 ? this.multiplyScalar( 1 / length ) : this.set( 0, 0, 0 );

		return this;

	},

	setLength: function( len ) {

		return this.normalize().multiplyScalar( len );

	},

	isZero: function () {

		var almostZero = 0.0001;
		return ( Math.abs( this.x ) < almostZero ) && ( Math.abs( this.y ) < almostZero ) && ( Math.abs( this.z ) < almostZero );

	},

	clone: function () {

		return new THREE.Vector3( this.x, this.y, this.z );

	},

	toString: function () {

		return 'THREE.Vector3 ( ' + this.x + ', ' + this.y + ', ' + this.z + ' )';

	}

};
<|endoftext|>


<commit_before>var lingcod = (function(){

    var options = {};
    var that = {};

    that.init = function(opts){
        options = opts;
        that.options = opts;

        $('#sidebar').tabs({
            select: function(event, ui){
                if($(this).hasClass('masked')){
                    event.preventDefault();
                }
            }
        });

        resize();

        if(window.google){
            google.earth.createInstance(
                "map",
                function(i){
                    geInit(i);
                },
                function(code){
                    geFailure(code);
                });
            setupListeners();
            lingcod.menu_items.init($('.menu_items'));
            // makes button clicking a lot more reliable!!
        }else{
            geFailure();
        }
        $(document).find('a.button').live('dragstart', function(){
            return false;
        });
    };

    var geInit = function(pluginInstance){
        ge = pluginInstance;
        ge.getWindow().setVisibility(true); // required
        ge.getOptions().setStatusBarVisibility(true);
        gex = new GEarthExtensions(ge);

        // that.googleLayers = new lingcod.map.googleLayers(ge,
        //     $('#ge_options'), $('#ge_layers'));
        that.geocoder = new lingcod.map.geocoder(gex, $('#flyToLocation'));
        that.measureTool = new lingcod.measureTool();

        $('#measure_distance').click(function(){
            that.measureTool.clear();
            that.measureTool.measureDistance(gex, "measureAmount");
            $('#measure_clear').removeClass('disabled');
            $('#measureAmountHolder').show();
        });
        $('#measure_area').click(function(){
            that.measureTool.clear();
            that.measureTool.measureArea(gex, "measureAmount");
            $('#measure_clear').removeClass('disabled');
            $('#measureAmountHolder').show();
        });
        $('#measure_clear').click(function(){
            that.measureTool.clear();
            $(this).addClass('disabled');
            $('#measureAmountHolder').hide();
        });
        $('#measure_units').change(function(){
            that.measureTool.setUnits($(this).val());
        });

        $('#datalayerstree').append('

');

        var studyRegion = lingcod.kmlTree({
            url: window.studyregion,
            ge: ge,
            gex: gex,
            animate: false,
            map_div: $('#map'),
            element: $('#study_region'),
            trans: options.media_url + 'common/images/transparent.gif',
            title: true,
            restoreState: true
        });
        if(!setCameraFromLocalStorage()){
            $(studyRegion).bind('kmlLoaded', function(){
                $('#study_region').find('li').dblclick();
            });
        }
        studyRegion.load();

        var publicData = lingcod.kmlTree({
            url: window.public_data_layers,
            ge: ge,
            gex: gex,
            animate: false,
            map_div: $('#map'),
            element: $('#public_data'),
            trans: options.media_url + 'common/images/transparent.gif',
            title: true,
            restoreState: true
        });
        publicData.load();

        var googleLayers = lingcod.kmlTree({
            url: options.media_url + 'common/fixtures/earthLayers.kml',
            ge: ge,
            gex: gex,
            animate: false,
            map_div: $('#map'),
            element: $('#googlelayers'),
            trans: options.media_url + 'common/images/transparent.gif',
            title: true,
            restoreState: true,
            supportItemIcon: true,
            fireEvents: function(){
                return true;
            }
        });

        var updateGoogleLayers = function(tree){
            $('#googlelayers li').each(function(){
                var item = $(this);
                var name = item.find('span.name').text();
                switch(name){
                    case 'Grid':
                        ge.getOptions().setGridVisibility(item.hasClass('visible'));
                        break;
                    case '3d Buildings':
                        ge.getLayerRoot().enableLayerById(ge.LAYER_BUILDINGS, item.hasClass('visible'));
                        break;
                    case 'Grey 3d Buildings':
                        ge.getLayerRoot().enableLayerById(ge.LAYER_BUILDINGS_LOW_RESOLUTION, item.hasClass('visible'));
                        break;
                    case 'Roads':
                        ge.getLayerRoot().enableLayerById(ge.LAYER_ROADS, item.hasClass('visible'));
                        break;
                    case 'Borders and Labels':
                        ge.getLayerRoot().enableLayerById(ge.LAYER_BORDERS, item.hasClass('visible'));
                        break;
                }
            });
        }

        $(googleLayers).bind('kmlLoaded', function(){
            updateGoogleLayers(googleLayers);
        });

        $(googleLayers).bind('toggleItem', function(){
            updateGoogleLayers(googleLayers);
        });

        googleLayers.load();

        var panel = lingcod.panel({appendTo: $('#panel-holder'),
            showCloseButton: false});

        that.client = lingcod.rest.client(gex, panel);

        if(typeof options.form_shown === 'function'){
            $(that.client).bind('form_shown', options.form_shown);
        }

        if(options.ecotrust){
            var ecotrustData = lingcod.kmlTree({
                url: options.ecotrust,
                ge: ge,
                gex: gex,
                animate: false,
                map_div: $('#map'),
                element: $('#ecotrust_data'),
                trans: options.media_url + 'common/images/transparent.gif',
                title: true,
                restoreState: true
            });
            ecotrustData.load();
        }

        var editors = [];

        if(options.myshapes){
            for(var i=0;i<options.myshapes.length; i++){
                var url = options.myshapes[i].url;
                var callback = options.myshapes[i]['callback'];
                var editor = lingcod.rest.kmlEditor({
                    ge: ge,
                    gex: gex,
                    appendTo: '#myshapestree',
                    div: '#map',
                    url: options.myshapes[i].url,
                    client: that.client,
                    shared: false,
                    allow_copy: options.allow_copy
                });
                if(callback){
                    $(editor.tree).bind('kmlLoaded', function(kmlObject){
                        callback(editor, editor.el, kmlObject)
                    });
                }
                editors.push(editor);
            }
        }

        if(options.sharedshapes){
            for(var i=0;i<options.sharedshapes.length; i++){
                editors.push(lingcod.rest.kmlEditor({
                    ge: ge,
                    gex: gex,
                    appendTo: '#sharedshapestree',
                    div: '#map',
                    url: options.sharedshapes[i],
                    client: that.client,
                    shared: true,
                    allow_copy: options.allow_copy
                }));
            }
        }

        $('#sidebar, #meta-navigation').click(function(e){
            if(e.target === this || e.target === $('#MyShapes')[0]){
                for(var i=0;i<editors.length;i++){
                    editors[i].clearSelection();
                }
            }
        });

        $('#news').click(function(e){
            opts = {};
            opts['load_msg'] = 'Loading News';
            opts['showClose'] = true;
            panel.showUrl(that.options.news_url, opts);
            e.preventDefault();
        });

        $('#about').click(function(e){
            opts = {};
            opts['load_msg'] = 'Loading Intro';
            opts['showClose'] = true;
            panel.showUrl(that.options.about_url, opts);
            e.preventDefault();
        });

        if (options.show_panel){
            opts = {};
            opts['showClose'] = true;
            if (options.show_panel == 'about') {
                panel.showUrl(that.options.about_url, opts);
            } else if (options.show_panel == 'news') {
                panel.showUrl(that.options.news_url, opts);
            }
        }

        var url = that.options.media_url + 'common/kml/shadow.kmz';
        google.earth.fetchKml(ge, url, function(k){
            ge.getFeatures().appendChild(k);
        });

        var setEarthOptions = function(){
            $('#earthOptions li').each(function(){
                var li = $(this);
                switch(li.attr('id')){
                    case 'nav':
                        if(li.hasClass('visible')){
                            ge.getNavigationControl().setVisibility(ge.VISIBILITY_AUTO);
                        }else{
                            ge.getNavigationControl().setVisibility(ge.VISIBILITY_HIDE);
                        }
                        break;
                    case 'overview':
                        ge.getOptions().setOverviewMapVisibility(li.hasClass('visible'));
                        break;
                    case 'scale':
                        ge.getOptions().setScaleLegendVisibility(li.hasClass('visible'));
                        break;
                    case 'atm':
                        ge.getOptions().setAtmosphereVisibility(li.hasClass('visible'));
                        break;
                    case 'terrain':
                        ge.getLayerRoot().enableLayerById(ge.LAYER_TERRAIN, li.hasClass('visible'));
                        break;
                }
            });
        }

        $('#earthOptions li').click(function(e){
            $(this).toggleClass('visible');
            setEarthOptions();
        });

        setEarthOptionsFromLocalStore();
        setEarthOptions();

        var unload = function(){
            setCameraToLocalStorage();
            saveEarthOptionsToLocalStore();
            $(window).die('beforunload', unload);
        }

        $(window).bind('beforeunload', unload);
    };

    var studyRegionLoaded = function(kmlObject, node){
        // Reorder so studyRegion is on top of the list
        $('#datalayerstree').prepend(node);
        if (kmlObject.getAbstractView()){
            ge.getView().setAbstractView(kmlObject.getAbstractView());
        }
    };

    var setEarthOptionsFromLocalStore = function(){
        if(!!window.localStorage && localStorage.getItem('earthOptions')){
            var json = JSON.parse(localStorage.getItem('earthOptions'));
            for(key in json){
                $('#earthOptions').find('#'+key).toggleClass('visible', json[key]);
            }
        }else{
            return false;
        }
    };

    var saveEarthOptionsToLocalStore = function(){
        if(!!window.localStorage){
            var json = {};
            $('#earthOptions li').each(function(){
                json[$(this).attr('id')] = $(this).hasClass('visible');
            });
            localStorage.setItem('earthOptions', JSON.stringify(json));
        }
    };

    var geFailure = function(errorCode){
        // alert("Failure loading the Google Earth Plugin: " + errorCode);
    }

    var setupListeners = function(){
        $(window).smartresize(function(){
            resize();
        });
        $('#meta-navigation').click(function(){
            lingcod.menu_items.closeAll();
        });
        $('#sidebar').bind('mouseup', function(e){
            lingcod.menu_items.closeAll();
            // return false;
        });
        $('#sidebar-mask').click(function(){
            lingcod.menu_items.closeAll();
        });
        $('#panel-holder').click(function(e){
            if(e.originalTarget === this){
                lingcod.menu_items.closeAll();
            }
        });
    };

    var resize = function(){
        var mh = $('#meta-navigation').outerHeight();
        var h = $(document.body).height() - mh;
        $('#sidebar').css({top: mh, height: h});
        $('#panel-holder').css({top: mh, height: h});

        var w = $(document.body).width() - $('#sidebar').width();
        $('#map_container').height(h).width(w);
    };

    that.maskSidebar = function(){
        $('#panel-holder').show();
        $('#sidebar').addClass('masked');
    };

    that.unmaskSidebar = function(){
        $('#panel-holder').hide();
        $('#sidebar').removeClass('masked');
    };

    that.showLoadingMask = function(msg){
        var msg = msg || 'Loading';
        var lmsg = $('#sidebar-mask').find('span.loadingMsg');
        lmsg.text(msg);
        lmsg.show();
        lingcod.menu_items.disable();
        $('#sidebar').addClass('masked');
    };

    that.hideLoadingMask = function(){
        $('#sidebar-mask').find('span.loadingMsg').hide();
        lingcod.menu_items.enable();
        that.unmaskSidebar();
    }

    var panels = [];

    that.addPanel = function(panel){
        panels.push(panel);
        $(panel).bind('panelshow', onPanelShown);
        $(panel).bind('panelhide', onPanelHide);
        $(panel).bind('panelclose', onPanelHide);
    },

    that.removePanel = function(panel){
        panels.remove(panel);
        $(panel).unbind('panelshow', onPanelShown);
        $(panel).unbind('panelhide', onPanelHide);
        $(panel).unbind('panelclose', onPanelHide);
    };

    var onPanelShown = function(e, panel){
        that.maskSidebar();
    };

    var onPanelHide = function(e, panel){
        var count = 0;
        for(var i=0; i<panels.length; i++){
            var p = panels[i];
            if(p.shown){
                count++;
            }
        }
        if(count <= 0){
            that.unmaskSidebar();
        }
    };

    var setCameraToLocalStorage = function(){
        if(!!window.localStorage){
            localStorage.setItem('marinemap-camera', gex.view.serialize());
        }
    };

    var setCameraFromLocalStorage = function(){
        if(!!window.localStorage && localStorage.getItem('marinemap-camera')){
            gex.view.deserialize(localStorage.getItem('marinemap-camera'));
            return true;
        }
        return false;
    };

    return that;
})();
<commit_msg>Restoring selected tab on browser refresh.<commit_after>var lingcod = (function(){

    var options = {};
    var that = {};

    that.init = function(opts){
        options = opts;
        that.options = opts;

        $('#sidebar').tabs({
            select: function(event, ui){
                if($(this).hasClass('masked')){
                    event.preventDefault();
                }
            }
        });

        var selectedTab = getStore('selectedTab');
        if(selectedTab){
            $('#sidebar').tabs('select', selectedTab);
        };

        resize();

        if(window.google){
            google.earth.createInstance(
                "map",
                function(i){
                    geInit(i);
                },
                function(code){
                    geFailure(code);
                });
            setupListeners();
            lingcod.menu_items.init($('.menu_items'));
            // makes button clicking a lot more reliable!!
        }else{
            geFailure();
        }
        $(document).find('a.button').live('dragstart', function(){
            return false;
        });
    };

    var geInit = function(pluginInstance){
        ge = pluginInstance;
        ge.getWindow().setVisibility(true); // required
        ge.getOptions().setStatusBarVisibility(true);
        gex = new GEarthExtensions(ge);

        // that.googleLayers = new lingcod.map.googleLayers(ge,
        //     $('#ge_options'), $('#ge_layers'));
        that.geocoder = new lingcod.map.geocoder(gex, $('#flyToLocation'));
        that.measureTool = new lingcod.measureTool();

        $('#measure_distance').click(function(){
            that.measureTool.clear();
            that.measureTool.measureDistance(gex, "measureAmount");
            $('#measure_clear').removeClass('disabled');
            $('#measureAmountHolder').show();
        });
        $('#measure_area').click(function(){
            that.measureTool.clear();
            that.measureTool.measureArea(gex, "measureAmount");
            $('#measure_clear').removeClass('disabled');
            $('#measureAmountHolder').show();
        });
        $('#measure_clear').click(function(){
            that.measureTool.clear();
            $(this).addClass('disabled');
            $('#measureAmountHolder').hide();
        });
        $('#measure_units').change(function(){
            that.measureTool.setUnits($(this).val());
        });

        $('#datalayerstree').append('

');

        var studyRegion = lingcod.kmlTree({
            url: window.studyregion,
            ge: ge,
            gex: gex,
            animate: false,
            map_div: $('#map'),
            element: $('#study_region'),
            trans: options.media_url + 'common/images/transparent.gif',
            title: true,
            restoreState: true
        });
        if(!setCameraFromLocalStorage()){
            $(studyRegion).bind('kmlLoaded', function(){
                $('#study_region').find('li').dblclick();
            });
        }
        studyRegion.load();

        var publicData = lingcod.kmlTree({
            url: window.public_data_layers,
            ge: ge,
            gex: gex,
            animate: false,
            map_div: $('#map'),
            element: $('#public_data'),
            trans: options.media_url + 'common/images/transparent.gif',
            title: true,
            restoreState: true
        });
        publicData.load();

        var googleLayers = lingcod.kmlTree({
            url: options.media_url + 'common/fixtures/earthLayers.kml',
            ge: ge,
            gex: gex,
            animate: false,
            map_div: $('#map'),
            element: $('#googlelayers'),
            trans: options.media_url + 'common/images/transparent.gif',
            title: true,
            restoreState: true,
            supportItemIcon: true,
            fireEvents: function(){
                return true;
            }
        });

        var updateGoogleLayers = function(tree){
            $('#googlelayers li').each(function(){
                var item = $(this);
                var name = item.find('span.name').text();
                switch(name){
                    case 'Grid':
                        ge.getOptions().setGridVisibility(item.hasClass('visible'));
                        break;
                    case '3d Buildings':
                        ge.getLayerRoot().enableLayerById(ge.LAYER_BUILDINGS, item.hasClass('visible'));
                        break;
                    case 'Grey 3d Buildings':
                        ge.getLayerRoot().enableLayerById(ge.LAYER_BUILDINGS_LOW_RESOLUTION, item.hasClass('visible'));
                        break;
                    case 'Roads':
                        ge.getLayerRoot().enableLayerById(ge.LAYER_ROADS, item.hasClass('visible'));
                        break;
                    case 'Borders and Labels':
                        ge.getLayerRoot().enableLayerById(ge.LAYER_BORDERS, item.hasClass('visible'));
                        break;
                }
            });
        }

        $(googleLayers).bind('kmlLoaded', function(){
            updateGoogleLayers(googleLayers);
        });

        $(googleLayers).bind('toggleItem', function(){
            updateGoogleLayers(googleLayers);
        });

        googleLayers.load();

        var panel = lingcod.panel({appendTo: $('#panel-holder'),
            showCloseButton: false});

        that.client = lingcod.rest.client(gex, panel);

        if(typeof options.form_shown === 'function'){
            $(that.client).bind('form_shown', options.form_shown);
        }

        if(options.ecotrust){
            var ecotrustData = lingcod.kmlTree({
                url: options.ecotrust,
                ge: ge,
                gex: gex,
                animate: false,
                map_div: $('#map'),
                element: $('#ecotrust_data'),
                trans: options.media_url + 'common/images/transparent.gif',
                title: true,
                restoreState: true
            });
            ecotrustData.load();
        }

        var editors = [];

        if(options.myshapes){
            for(var i=0;i<options.myshapes.length; i++){
                var url = options.myshapes[i].url;
                var callback = options.myshapes[i]['callback'];
                var editor = lingcod.rest.kmlEditor({
                    ge: ge,
                    gex: gex,
                    appendTo: '#myshapestree',
                    div: '#map',
                    url: options.myshapes[i].url,
                    client: that.client,
                    shared: false,
                    allow_copy: options.allow_copy
                });
                if(callback){
                    $(editor.tree).bind('kmlLoaded', function(kmlObject){
                        callback(editor, editor.el, kmlObject)
                    });
                }
                editors.push(editor);
            }
        }

        if(options.sharedshapes){
            for(var i=0;i<options.sharedshapes.length; i++){
                editors.push(lingcod.rest.kmlEditor({
                    ge: ge,
                    gex: gex,
                    appendTo: '#sharedshapestree',
                    div: '#map',
                    url: options.sharedshapes[i],
                    client: that.client,
                    shared: true,
                    allow_copy: options.allow_copy
                }));
            }
        }

        $('#sidebar, #meta-navigation').click(function(e){
            if(e.target === this || e.target === $('#MyShapes')[0]){
                for(var i=0;i<editors.length;i++){
                    editors[i].clearSelection();
                }
            }
        });

        $('#news').click(function(e){
            opts = {};
            opts['load_msg'] = 'Loading News';
            opts['showClose'] = true;
            panel.showUrl(that.options.news_url, opts);
            e.preventDefault();
        });

        $('#about').click(function(e){
            opts = {};
            opts['load_msg'] = 'Loading Intro';
            opts['showClose'] = true;
            panel.showUrl(that.options.about_url, opts);
            e.preventDefault();
        });

        if (options.show_panel){
            opts = {};
            opts['showClose'] = true;
            if (options.show_panel == 'about') {
                panel.showUrl(that.options.about_url, opts);
            } else if (options.show_panel == 'news') {
                panel.showUrl(that.options.news_url, opts);
            }
        }

        var url = that.options.media_url + 'common/kml/shadow.kmz';
        google.earth.fetchKml(ge, url, function(k){
            ge.getFeatures().appendChild(k);
        });

        var setEarthOptions = function(){
            $('#earthOptions li').each(function(){
                var li = $(this);
                switch(li.attr('id')){
                    case 'nav':
                        if(li.hasClass('visible')){
                            ge.getNavigationControl().setVisibility(ge.VISIBILITY_AUTO);
                        }else{
                            ge.getNavigationControl().setVisibility(ge.VISIBILITY_HIDE);
                        }
                        break;
                    case 'overview':
                        ge.getOptions().setOverviewMapVisibility(li.hasClass('visible'));
                        break;
                    case 'scale':
                        ge.getOptions().setScaleLegendVisibility(li.hasClass('visible'));
                        break;
                    case 'atm':
                        ge.getOptions().setAtmosphereVisibility(li.hasClass('visible'));
                        break;
                    case 'terrain':
                        ge.getLayerRoot().enableLayerById(ge.LAYER_TERRAIN, li.hasClass('visible'));
                        break;
                }
            });
        }

        $('#earthOptions li').click(function(e){
            $(this).toggleClass('visible');
            setEarthOptions();
        });

        setEarthOptionsFromLocalStore();
        setEarthOptions();

        var unload = function(){
            setCameraToLocalStorage();
            saveEarthOptionsToLocalStore();
            setStore('selectedTab', $('#sidebar > ul > .ui-tabs-selected a').attr('href'));
            $(window).die('beforunload', unload);
        }

        $(window).bind('beforeunload', unload);
    };

    var studyRegionLoaded = function(kmlObject, node){
        // Reorder so studyRegion is on top of the list
        $('#datalayerstree').prepend(node);
        if (kmlObject.getAbstractView()){
            ge.getView().setAbstractView(kmlObject.getAbstractView());
        }
    };

    var setStore = function(key, value){
        if(!!window.localStorage){
            localStorage.setItem(key, value);
        }
    };

    var getStore = function(key){
        if(!!window.localStorage){
            return localStorage.getItem(key);
        }else{
            return false;
        }
    }

    var setEarthOptionsFromLocalStore = function(){
        if(!!window.localStorage && localStorage.getItem('earthOptions')){
            var json = JSON.parse(localStorage.getItem('earthOptions'));
            for(key in json){
                $('#earthOptions').find('#'+key).toggleClass('visible', json[key]);
            }
        }else{
            return false;
        }
    };

    var saveEarthOptionsToLocalStore = function(){
        if(!!window.localStorage){
            var json = {};
            $('#earthOptions li').each(function(){
                json[$(this).attr('id')] = $(this).hasClass('visible');
            });
            localStorage.setItem('earthOptions', JSON.stringify(json));
        }
    };

    var geFailure = function(errorCode){
        // alert("Failure loading the Google Earth Plugin: " + errorCode);
    }

    var setupListeners = function(){
        $(window).smartresize(function(){
            resize();
        });
        $('#meta-navigation').click(function(){
            lingcod.menu_items.closeAll();
        });
        $('#sidebar').bind('mouseup', function(e){
            lingcod.menu_items.closeAll();
            // return false;
        });
        $('#sidebar-mask').click(function(){
            lingcod.menu_items.closeAll();
        });
        $('#panel-holder').click(function(e){
            if(e.originalTarget === this){
                lingcod.menu_items.closeAll();
            }
        });
    };

    var resize = function(){
        var mh = $('#meta-navigation').outerHeight();
        var h = $(document.body).height() - mh;
        $('#sidebar').css({top: mh, height: h});
        $('#panel-holder').css({top: mh, height: h});

        var w = $(document.body).width() - $('#sidebar').width();
        $('#map_container').height(h).width(w);
    };

    that.maskSidebar = function(){
        $('#panel-holder').show();
        $('#sidebar').addClass('masked');
    };

    that.unmaskSidebar = function(){
        $('#panel-holder').hide();
        $('#sidebar').removeClass('masked');
    };

    that.showLoadingMask = function(msg){
        var msg = msg || 'Loading';
        var lmsg = $('#sidebar-mask').find('span.loadingMsg');
        lmsg.text(msg);
        lmsg.show();
        lingcod.menu_items.disable();
        $('#sidebar').addClass('masked');
    };

    that.hideLoadingMask = function(){
        $('#sidebar-mask').find('span.loadingMsg').hide();
        lingcod.menu_items.enable();
        that.unmaskSidebar();
    }

    var panels = [];

    that.addPanel = function(panel){
        panels.push(panel);
        $(panel).bind('panelshow', onPanelShown);
        $(panel).bind('panelhide', onPanelHide);
        $(panel).bind('panelclose', onPanelHide);
    },

    that.removePanel = function(panel){
        panels.remove(panel);
        $(panel).unbind('panelshow', onPanelShown);
        $(panel).unbind('panelhide', onPanelHide);
        $(panel).unbind('panelclose', onPanelHide);
    };

    var onPanelShown = function(e, panel){
        that.maskSidebar();
    };

    var onPanelHide = function(e, panel){
        var count = 0;
        for(var i=0; i<panels.length; i++){
            var p = panels[i];
            if(p.shown){
                count++;
            }
        }
        if(count <= 0){
            that.unmaskSidebar();
        }
    };

    var setCameraToLocalStorage = function(){
        if(!!window.localStorage){
            localStorage.setItem('marinemap-camera', gex.view.serialize());
        }
    };

    var setCameraFromLocalStorage = function(){
        if(!!window.localStorage && localStorage.getItem('marinemap-camera')){
            gex.view.deserialize(localStorage.getItem('marinemap-camera'));
            return true;
        }
        return false;
    };

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


<commit_before>export const DEBUG_FLAG = false;

// ***********************************************************
// This example support/index.js is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************

// Import commands.js using ES2015 syntax:
// import './commands';

// Alternatively you can use CommonJS syntax:
// require('./commands')

// You can mock if needed. Example below
// beforeEach(() => {
//     cy.server();
//     cy.route('/countries*', {});
// })

/* returning false here prevents Cypress from failing the test */
Cypress.on('uncaught:exception', (err, runnable) => false);

Cypress.Commands.overwrite(
  'type',
  (originalFn, subject, string, options) => originalFn(
    subject,
    string,
    Object.assign({}, options, { delay: 100 }),
  ),
);

function getItem(selector, counter) {
  cy.wait(50, { log: DEBUG_FLAG })
    .get('#storybook-preview-iframe', { log: DEBUG_FLAG })
    .then(($iframe) => {
      if (!$iframe.contents().find(selector).length && counter > 0) {
        return getItem(selector, --counter);
      }
      return cy.wrap($iframe.contents().find(selector));
    });
}

Cypress.Commands.add('iFrame', (selector) => { getItem(selector, 20); });
<commit_msg>increase waiting for special elements time from 1sec to 2sec<commit_after>export const DEBUG_FLAG = false;

// ***********************************************************
// This example support/index.js is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************

// Import commands.js using ES2015 syntax:
// import './commands';

// Alternatively you can use CommonJS syntax:
// require('./commands')

// You can mock if needed. Example below
// beforeEach(() => {
//     cy.server();
//     cy.route('/countries*', {});
// })

/* returning false here prevents Cypress from failing the test */
Cypress.on('uncaught:exception', (err, runnable) => false);

Cypress.Commands.overwrite(
  'type',
  (originalFn, subject, string, options) => originalFn(
    subject,
    string,
    Object.assign({}, options, { delay: 100 }),
  ),
);

function getItem(selector, counter) {
  cy.wait(50, { log: DEBUG_FLAG })
    .get('#storybook-preview-iframe', { log: DEBUG_FLAG })
    .then(($iframe) => {
      if (!$iframe.contents().find(selector).length && counter > 0) {
        return getItem(selector, --counter);
      }
      return cy.wrap($iframe.contents().find(selector));
    });
}

Cypress.Commands.add('iFrame', (selector) => { getItem(selector, 40); });
<|endoftext|>