<commit_before>import _ from 'lodash';

import Dispatcher from '../dispatcher/AppDispatcher';
import Constants  from '../constants/Constants';

import SonosService from '../services/SonosService';
import MusicServiceClient from '../services/MusicServiceClient';

import QueueStore from '../stores/QueueStore';
import BrowserListStore from '../stores/BrowserListStore';

export default {

	_getItem (item) {
		if(!item.serviceClient) {
			return Promise.resolve(item);
		}

		let client = item.serviceClient;
		let serviceType = client._serviceDefinition.ServiceIDEncoded

		let settingsMatch = _.find(SonosService._accountInfo, { Type: String(serviceType) } );

		if(settingsMatch) {
			let uri = client.getTrackURI(item.id, client._serviceDefinition.Id, settingsMatch.SerialNum);
			let token = client.getServiceString(serviceType, settingsMatch.Username);
			let meta = client.encodeItemMetadata(uri, item, token);

			return Promise.resolve({
				uri: _.escape(uri),
				metadata: meta,
			});
		}

		return client.getMediaURI(item.id)
				.then((uri) => {
					return {
						uri: _.escape(uri),
						metadata: client.encodeItemMetadata(uri, item),
					};
				});
	},

	back () {
		Dispatcher.dispatch({
			actionType: Constants.BROWSER_BACK,
		});
	},

	home () {
		Dispatcher.dispatch({
			actionType: Constants.BROWSER_HOME,
		});
	},

	more (state) {
		let sonos = SonosService._currentDevice;
		let params = {
			start: state.items.length
		};

		let client = state.serviceClient;

		if(client && state.total > state.items.length) {
			client.getMetadata(state.parent.id, state.items.length, state.items.length + 100)
				.then((res) => {
					let items = [];

					if(res.mediaMetadata) {
						if(!_.isArray(res.mediaMetadata)) {
							res.mediaMetadata = [res.mediaMetadata];
						}

						res.mediaMetadata.forEach((i) => {
							i.serviceClient = client;
							items[i.$$position] =  i;
						})
					}

					if(res.mediaCollection) {
						if(!_.isArray(res.mediaCollection)) {
							res.mediaCollection = [res.mediaCollection];
						}

						res.mediaCollection.forEach((i) => {
							i.serviceClient = client;
							items[i.$$position] =  i;
						})
					}

					state.items = state.items.concat(items);
					state.total = res.total || state.total;

					Dispatcher.dispatch({
						actionType: Constants.BROWSER_SCROLL_RESULT,
						state: state,
					});
				})

			return;
		} else {
			sonos.getMusicLibrary(state.id || state.searchType, params, (err, result) => {
				if(err || !result || !result.items) {
					return;
				}

				state.items = state.items.concat(result.items);

				Dispatcher.dispatch({
					actionType: Constants.BROWSER_SCROLL_RESULT,
					state: state,
				});
			});
		}
	},

	playNow (eventTarget) {
		this._getItem(eventTarget).then((item) => {
			let sonos = SonosService._currentDevice;

			if(item.metadata && item.metadataRaw && item.metadata.class === 'object.item.audioItem.audioBroadcast') {
				sonos.play({
					uri: item.uri,
					metadata: item.metadataRaw,
				}, () => {
					SonosService.queryState(sonos);
				});
			} else if(item.class && item.class === 'object.item.audioItem') {
				sonos.play(item.uri, () => {
					SonosService.queryState(sonos);
				});
			} else {
				sonos.getMusicLibrary('queue', {total: 0}, (err, res) => {
					if(err) {
						return;
					}

					let pos = 1;
					if(res.total) {
						pos = Number(res.total) + 1;
					}
					sonos.queue(item, () => {
						sonos.goto(pos, () => {
							sonos.play(() => {
								SonosService.queryState(sonos);
							});
						});
					});
				});
			}
		});
	},

	playNext (eventTarget) {
		this._getItem(eventTarget).then((item) => {
			let sonos = SonosService._currentDevice;

			sonos.getPositionInfo((err, info) => {
				let pos = Number(info.Track) + 1;
				sonos.queue(item, pos, () => {
					SonosService.queryState(sonos);
				});
			});
		});
	},

	addQueue (eventTarget) {
		this._getItem(eventTarget).then((item) => {
			let sonos = SonosService._currentDevice;

			sonos.queue(item, () => {
				SonosService.queryState(sonos);
			});
		});
	},

	replaceQueue (eventTarget) {
		this._getItem(eventTarget).then((item) => {
			let sonos = SonosService._currentDevice;

			sonos.flush(() => {
				sonos.queue(item, () => {
					sonos.play(() => {
						SonosService.queryState(sonos);
					});
				});
			});
		});
	},

	removeService (service) {
		SonosService.removeMusicService(service.service);
	},

	_fetchLineIns () {
		let promises = [];

		Object.keys(SonosService._deviceSearches).forEach((host) => {
			promises.push(new Promise((resolve, reject) => {
				let sonos = SonosService._deviceSearches[host];

				sonos.getMusicLibrary('AI:', {}, (err, result) => {
					let items = (result && result.items) ? result.items : [];

					if(items.length === 0) {
						resolve(items);
						return;
					}

					sonos.getZoneAttrs((err1, data) => {
						items.forEach((i) => {
							i.title = i.title + ': ' + data.CurrentZoneName;
						});
						resolve(items);
					});
				})
			}));
		});

		return Promise.all(promises).then((arr) => {
			return _.flatten(arr);
		});
	},

	_fetchMusicServices () {
		const ALLOWED_SERVICES = [12, 160]; // 12 is spotify, 160 soundcloud
		let sonos = SonosService._currentDevice;
		let existingIds = SonosService._musicServices.map(s => s.service.Id);

		let promise= new Promise((resolve, reject) => {
			sonos.getAvailableServices((err, data) => {

				data = _.reject(data, { Auth: "UserId" });
				data = _.reject(data, (item) => {
					return _.contains(existingIds, item.Id);
				});
				data = _.filter(data, (item) => {
					return _.contains(ALLOWED_SERVICES, Number(item.Id));
				});

				resolve(data.map((out) => {
					return {
						action: 'addService',
						title: out.Name,
						id: Number(out.Id),
						data: out,
					};
				}));
			});
		});

		return promise;
	},

	select (item) {

		let sonos = SonosService._currentDevice;
		let prendinBrowserUpdate;
		let objectId = item.searchType;

		if(item.action && item.action === 'library') {
			Dispatcher.dispatch({
				actionType: Constants.BROWSER_SELECT_ITEM,
				state: BrowserListStore.LIBRARY_STATE,
			});
			return;
		}

		if(item.action && item.action === 'linein') {
			this._fetchLineIns().then((results) => {
				let state = _.cloneDeep(item);
				state.items = results || [];

				Dispatcher.dispatch({
					actionType: Constants.BROWSER_SELECT_ITEM,
					state: state,
				});
			});
			return;
		}

		if(item.action && item.action === 'browseServices') {
			this._fetchMusicServices().then((results) => {
				let state = _.cloneDeep(item);
				state.items = results || [];

				Dispatcher.dispatch({
					actionType: Constants.BROWSER_SELECT_ITEM,
					state: state,
				});
			});
			return;
		}

		if(item.action && item.action === 'addService') {
			Dispatcher.dispatch({
				actionType: Constants.BROWSER_ADD_MUSICSERVICE,
				service: new MusicServiceClient(item.data)
			});
			return;
		}

		if(item.action && item.action === 'service') {
			let client = new MusicServiceClient(item.service.service);
			client.setAuthToken(item.service.authToken.authToken);
			client.setKey(item.service.authToken.privateKey);

			client.getMetadata('root', 0, 100)
				.then((res) => {
					let state = {
						title: client.name,
						serviceClient: client,
						items: res.mediaCollection.map((i) => {
							i.serviceClient = client;
							return i;
						}),
					};

					Dispatcher.dispatch({
						actionType: Constants.BROWSER_SELECT_ITEM,
						state: state,
					});
				});
			return;
		}

		if(item.serviceClient && item.itemType !== 'track') {
			let client = item.serviceClient;

			client.getMetadata(item.id, 0, 100)
				.then((res) => {
					let items = [];

					if(res.mediaMetadata) {
						if(!_.isArray(res.mediaMetadata)) {
							res.mediaMetadata = [res.mediaMetadata];
						}

						res.mediaMetadata.forEach((i) => {
							i.serviceClient = client;
							items[i.$$position] =  i;
						})
					}

					if(res.mediaCollection) {
						if(!_.isArray(res.mediaCollection)) {
							res.mediaCollection = [res.mediaCollection];
						}

						res.mediaCollection.forEach((i) => {
							i.serviceClient = client;
							items[i.$$position] =  i;
						})
					}

					let state = {
						title: item.title,
						parent: item,
						serviceClient: client,
						total: res.total,
						items: _.without(items, undefined),
					};

					Dispatcher.dispatch({
						actionType: Constants.BROWSER_SELECT_ITEM,
						state: state,
					});
				})

			return;
		}

		if(item.searchType) {
			prendinBrowserUpdate = {
				title : item.title,
				searchType : item.searchType
			};
		} else {
			prendinBrowserUpdate = item;
		}

		if(item.class) {
			objectId = (item.id) ? item.id : item.uri.split('#')[1];
		}

		sonos.getMusicLibrary(objectId, {}, (err, result) => {
			var state = prendinBrowserUpdate;
			state.items = result.items;

			Dispatcher.dispatch({
				actionType: Constants.BROWSER_SELECT_ITEM,
				state: state,
			});
		});
	},

	changeSearchMode (mode) {
		Dispatcher.dispatch({
			actionType: Constants.BROWSER_CHANGE_SEARCH_MODE,
			mode: mode,
		});
	}
};
<commit_msg>Bugfix lodash legacy function on add services<commit_after>import _ from 'lodash';

import Dispatcher from '../dispatcher/AppDispatcher';
import Constants  from '../constants/Constants';

import SonosService from '../services/SonosService';
import MusicServiceClient from '../services/MusicServiceClient';

import QueueStore from '../stores/QueueStore';
import BrowserListStore from '../stores/BrowserListStore';

export default {

	_getItem (item) {
		if(!item.serviceClient) {
			return Promise.resolve(item);
		}

		let client = item.serviceClient;
		let serviceType = client._serviceDefinition.ServiceIDEncoded

		let settingsMatch = _.find(SonosService._accountInfo, { Type: String(serviceType) } );

		if(settingsMatch) {
			let uri = client.getTrackURI(item.id, client._serviceDefinition.Id, settingsMatch.SerialNum);
			let token = client.getServiceString(serviceType, settingsMatch.Username);
			let meta = client.encodeItemMetadata(uri, item, token);

			return Promise.resolve({
				uri: _.escape(uri),
				metadata: meta,
			});
		}

		return client.getMediaURI(item.id)
				.then((uri) => {
					return {
						uri: _.escape(uri),
						metadata: client.encodeItemMetadata(uri, item),
					};
				});
	},

	back () {
		Dispatcher.dispatch({
			actionType: Constants.BROWSER_BACK,
		});
	},

	home () {
		Dispatcher.dispatch({
			actionType: Constants.BROWSER_HOME,
		});
	},

	more (state) {
		let sonos = SonosService._currentDevice;
		let params = {
			start: state.items.length
		};

		let client = state.serviceClient;

		if(client && state.total > state.items.length) {
			client.getMetadata(state.parent.id, state.items.length, state.items.length + 100)
				.then((res) => {
					let items = [];

					if(res.mediaMetadata) {
						if(!_.isArray(res.mediaMetadata)) {
							res.mediaMetadata = [res.mediaMetadata];
						}

						res.mediaMetadata.forEach((i) => {
							i.serviceClient = client;
							items[i.$$position] =  i;
						})
					}

					if(res.mediaCollection) {
						if(!_.isArray(res.mediaCollection)) {
							res.mediaCollection = [res.mediaCollection];
						}

						res.mediaCollection.forEach((i) => {
							i.serviceClient = client;
							items[i.$$position] =  i;
						})
					}

					state.items = state.items.concat(items);
					state.total = res.total || state.total;

					Dispatcher.dispatch({
						actionType: Constants.BROWSER_SCROLL_RESULT,
						state: state,
					});
				})

			return;
		} else {
			sonos.getMusicLibrary(state.id || state.searchType, params, (err, result) => {
				if(err || !result || !result.items) {
					return;
				}

				state.items = state.items.concat(result.items);

				Dispatcher.dispatch({
					actionType: Constants.BROWSER_SCROLL_RESULT,
					state: state,
				});
			});
		}
	},

	playNow (eventTarget) {
		this._getItem(eventTarget).then((item) => {
			let sonos = SonosService._currentDevice;

			if(item.metadata && item.metadataRaw && item.metadata.class === 'object.item.audioItem.audioBroadcast') {
				sonos.play({
					uri: item.uri,
					metadata: item.metadataRaw,
				}, () => {
					SonosService.queryState(sonos);
				});
			} else if(item.class && item.class === 'object.item.audioItem') {
				sonos.play(item.uri, () => {
					SonosService.queryState(sonos);
				});
			} else {
				sonos.getMusicLibrary('queue', {total: 0}, (err, res) => {
					if(err) {
						return;
					}

					let pos = 1;
					if(res.total) {
						pos = Number(res.total) + 1;
					}
					sonos.queue(item, () => {
						sonos.goto(pos, () => {
							sonos.play(() => {
								SonosService.queryState(sonos);
							});
						});
					});
				});
			}
		});
	},

	playNext (eventTarget) {
		this._getItem(eventTarget).then((item) => {
			let sonos = SonosService._currentDevice;

			sonos.getPositionInfo((err, info) => {
				let pos = Number(info.Track) + 1;
				sonos.queue(item, pos, () => {
					SonosService.queryState(sonos);
				});
			});
		});
	},

	addQueue (eventTarget) {
		this._getItem(eventTarget).then((item) => {
			let sonos = SonosService._currentDevice;

			sonos.queue(item, () => {
				SonosService.queryState(sonos);
			});
		});
	},

	replaceQueue (eventTarget) {
		this._getItem(eventTarget).then((item) => {
			let sonos = SonosService._currentDevice;

			sonos.flush(() => {
				sonos.queue(item, () => {
					sonos.play(() => {
						SonosService.queryState(sonos);
					});
				});
			});
		});
	},

	removeService (service) {
		SonosService.removeMusicService(service.service);
	},

	_fetchLineIns () {
		let promises = [];

		Object.keys(SonosService._deviceSearches).forEach((host) => {
			promises.push(new Promise((resolve, reject) => {
				let sonos = SonosService._deviceSearches[host];

				sonos.getMusicLibrary('AI:', {}, (err, result) => {
					let items = (result && result.items) ? result.items : [];

					if(items.length === 0) {
						resolve(items);
						return;
					}

					sonos.getZoneAttrs((err1, data) => {
						items.forEach((i) => {
							i.title = i.title + ': ' + data.CurrentZoneName;
						});
						resolve(items);
					});
				})
			}));
		});

		return Promise.all(promises).then((arr) => {
			return _.flatten(arr);
		});
	},

	_fetchMusicServices () {
		const ALLOWED_SERVICES = [12, 160]; // 12 is spotify, 160 soundcloud
		let sonos = SonosService._currentDevice;
		let existingIds = SonosService._musicServices.map(s => s.service.Id);

		let promise= new Promise((resolve, reject) => {
			sonos.getAvailableServices((err, data) => {

				data = _.reject(data, { Auth: "UserId" });
				data = _.reject(data, (item) => {
					return _.includes(existingIds, item.Id);
				});
				data = _.filter(data, (item) => {
					return _.includes(ALLOWED_SERVICES, Number(item.Id));
				});

				resolve(data.map((out) => {
					return {
						action: 'addService',
						title: out.Name,
						id: Number(out.Id),
						data: out,
					};
				}));
			});
		});

		return promise;
	},

	select (item) {

		let sonos = SonosService._currentDevice;
		let prendinBrowserUpdate;
		let objectId = item.searchType;

		if(item.action && item.action === 'library') {
			Dispatcher.dispatch({
				actionType: Constants.BROWSER_SELECT_ITEM,
				state: BrowserListStore.LIBRARY_STATE,
			});
			return;
		}

		if(item.action && item.action === 'linein') {
			this._fetchLineIns().then((results) => {
				let state = _.cloneDeep(item);
				state.items = results || [];

				Dispatcher.dispatch({
					actionType: Constants.BROWSER_SELECT_ITEM,
					state: state,
				});
			});
			return;
		}

		if(item.action && item.action === 'browseServices') {
			this._fetchMusicServices().then((results) => {
				let state = _.cloneDeep(item);
				state.items = results || [];

				Dispatcher.dispatch({
					actionType: Constants.BROWSER_SELECT_ITEM,
					state: state,
				});
			});
			return;
		}

		if(item.action && item.action === 'addService') {
			Dispatcher.dispatch({
				actionType: Constants.BROWSER_ADD_MUSICSERVICE,
				service: new MusicServiceClient(item.data)
			});
			return;
		}

		if(item.action && item.action === 'service') {
			let client = new MusicServiceClient(item.service.service);
			client.setAuthToken(item.service.authToken.authToken);
			client.setKey(item.service.authToken.privateKey);

			client.getMetadata('root', 0, 100)
				.then((res) => {
					let state = {
						title: client.name,
						serviceClient: client,
						items: res.mediaCollection.map((i) => {
							i.serviceClient = client;
							return i;
						}),
					};

					Dispatcher.dispatch({
						actionType: Constants.BROWSER_SELECT_ITEM,
						state: state,
					});
				});
			return;
		}

		if(item.serviceClient && item.itemType !== 'track') {
			let client = item.serviceClient;

			client.getMetadata(item.id, 0, 100)
				.then((res) => {
					let items = [];

					if(res.mediaMetadata) {
						if(!_.isArray(res.mediaMetadata)) {
							res.mediaMetadata = [res.mediaMetadata];
						}

						res.mediaMetadata.forEach((i) => {
							i.serviceClient = client;
							items[i.$$position] =  i;
						})
					}

					if(res.mediaCollection) {
						if(!_.isArray(res.mediaCollection)) {
							res.mediaCollection = [res.mediaCollection];
						}

						res.mediaCollection.forEach((i) => {
							i.serviceClient = client;
							items[i.$$position] =  i;
						})
					}

					let state = {
						title: item.title,
						parent: item,
						serviceClient: client,
						total: res.total,
						items: _.without(items, undefined),
					};

					Dispatcher.dispatch({
						actionType: Constants.BROWSER_SELECT_ITEM,
						state: state,
					});
				})

			return;
		}

		if(item.searchType) {
			prendinBrowserUpdate = {
				title : item.title,
				searchType : item.searchType
			};
		} else {
			prendinBrowserUpdate = item;
		}

		if(item.class) {
			objectId = (item.id) ? item.id : item.uri.split('#')[1];
		}

		sonos.getMusicLibrary(objectId, {}, (err, result) => {
			var state = prendinBrowserUpdate;
			state.items = result.items;

			Dispatcher.dispatch({
				actionType: Constants.BROWSER_SELECT_ITEM,
				state: state,
			});
		});
	},

	changeSearchMode (mode) {
		Dispatcher.dispatch({
			actionType: Constants.BROWSER_CHANGE_SEARCH_MODE,
			mode: mode,
		});
	}
};
<|endoftext|>


<commit_before>import fetch from './fetch.js'
import addCacheBustToQuery from './common/add-cache-bust-to-query.js'

export default function checkIfFileExists (url) {
  return fetch(
    addCacheBustToQuery(url),
    {
      method: 'HEAD',
      cache: 'reload'
    }
  ).then(function onSuccess(response){
    // response.ok provides boolean type information on request status
    // https://developer.mozilla.org/en-US/docs/Web/API/Response/ok
    return response.ok
  }, function onReject(){
    return false
  })
}<commit_msg>adds param check<commit_after>import fetch from './fetch.js'
import addCacheBustToQuery from './common/add-cache-bust-to-query.js'

export default function checkIfFileExists (url) {

  if (!url) return Promise.reject('Please provide file URL string as param.')

  return fetch( addCacheBustToQuery(url), {
    method: 'HEAD',
    cache: 'reload'
  }).then(function onSuccess (response) {
    // response.ok provides boolean type information on request status
    // https://developer.mozilla.org/en-US/docs/Web/API/Response/ok
    return response.ok
  }, function onReject () {
    return false
  })
}<|endoftext|>


<commit_before>import dom from "../dom";
import { Constants } from "../constants";
import { formatInline } from "./formatInline";

var undef,
    NODE_NAME = "A";

function _removeFormat(composer, anchors) {
  var length  = anchors.length,
      i       = 0,
      anchor,
      codeElement,
      textContent;
  for (; i<length; i++) {
    anchor      = anchors[i];
    codeElement = composer.parentElement(anchor, { nodeName: "code" });
    textContent = dom.getTextContent(anchor);

    // if <a> contains url-like text content, rename it to <code> to prevent re-autolinking
    // else replace <a> with its childNodes
    if (textContent.match(Constants.URL_REG_EXP) && !codeElement) {
      // <code> element is used to prevent later auto-linking of the content
      codeElement = dom.renameElement(anchor, "code");
    } else {
      dom.replaceWithChildNodes(anchor);
    }
  }
}

function _format(composer, attributes) {
  var doc             = composer.doc,
      tempClass       = "_wysihtml5-temp-" + (+new Date()),
      tempClassRegExp = /non-matching-class/g,
      i               = 0,
      length,
      anchors,
      anchor,
      hasElementChild,
      isEmpty,
      elementToSetCaretAfter,
      textContent,
      whiteSpace,
      j;

  formatInline.exec(composer, undef, NODE_NAME, tempClass, tempClassRegExp);
  anchors = doc.querySelectorAll(NODE_NAME + "." + tempClass);
  length  = anchors.length;
  for (; i<length; i++) {
    anchor = anchors[i];
    anchor.removeAttribute("class");
    for (j in attributes) {
      anchor.setAttribute(j, attributes[j]);
    }
  }

  elementToSetCaretAfter = anchor;
  if (length === 1) {
    textContent = dom.getTextContent(anchor);
    hasElementChild = !!anchor.querySelector("*");
    isEmpty = textContent === "" || textContent === Constants.INVISIBLE_SPACE;
    if (!hasElementChild && isEmpty) {
      dom.setTextContent(anchor, attributes.text || anchor.href);
      whiteSpace = doc.createTextNode(" ");
      composer.selection.setAfter(anchor);
      dom.insert(whiteSpace).after(anchor);
      elementToSetCaretAfter = whiteSpace;
    }
  }
  composer.selection.setAfter(elementToSetCaretAfter);
  return anchors;
}

var createLink = {
  /**
   * TODO: Use HTMLApplier or formatInline here
   *
   * Turns selection into a link
   * If selection is already a link, it removes the link and wraps it with a <code> element
   * The <code> element is needed to avoid auto linking
   *
   * @example
   *    // either ...
   *    wysihtml5.commands.createLink.exec(composer, "createLink", "http://www.google.de");
   *    // ... or ...
   *    wysihtml5.commands.createLink.exec(composer, "createLink", { href: "http://www.google.de", target: "_blank" });
   */
  exec: function(composer, command, value) {
    var anchors = this.state(composer, command);
    if (anchors) {
      // Selection contains links
      composer.selection.executeAndRestore(function() {
        _removeFormat(composer, anchors);
      });
    } else {
      // Create links
      value = typeof(value) === "object" ? value : { href: value };
      return _format(composer, value);
    }
  },

  state: function(composer, command) {
    return formatInline.state(composer, command, "A");
  }
};

export { createLink };
<commit_msg>Always insert ws after generating link<commit_after>import dom from "../dom";
import { Constants } from "../constants";
import { formatInline } from "./formatInline";

var undef,
    NODE_NAME = "A";

function _removeFormat(composer, anchors) {
  var length  = anchors.length,
      i       = 0,
      anchor,
      codeElement,
      textContent;
  for (; i<length; i++) {
    anchor      = anchors[i];
    codeElement = composer.parentElement(anchor, { nodeName: "code" });
    textContent = dom.getTextContent(anchor);

    // if <a> contains url-like text content, rename it to <code> to prevent re-autolinking
    // else replace <a> with its childNodes
    if (textContent.match(Constants.URL_REG_EXP) && !codeElement) {
      // <code> element is used to prevent later auto-linking of the content
      codeElement = dom.renameElement(anchor, "code");
    } else {
      dom.replaceWithChildNodes(anchor);
    }
  }
}

function _format(composer, attributes) {
  var doc             = composer.doc,
      tempClass       = "_wysihtml5-temp-" + (+new Date()),
      tempClassRegExp = /non-matching-class/g,
      i               = 0,
      length,
      anchors,
      anchor,
      hasElementChild,
      isEmpty,
      elementToSetCaretAfter,
      textContent,
      whiteSpace,
      j;

  formatInline.exec(composer, undef, NODE_NAME, tempClass, tempClassRegExp);
  anchors = doc.querySelectorAll(NODE_NAME + "." + tempClass);
  length  = anchors.length;
  for (; i<length; i++) {
    anchor = anchors[i];
    anchor.removeAttribute("class");
    for (j in attributes) {
      anchor.setAttribute(j, attributes[j]);
    }
  }

  elementToSetCaretAfter = anchor;
  if (length === 1) {
    textContent = dom.getTextContent(anchor);
    hasElementChild = !!anchor.querySelector("*");
    isEmpty = textContent === "" || textContent === Constants.INVISIBLE_SPACE;
    if (!hasElementChild && isEmpty) {
      dom.setTextContent(anchor, attributes.text || anchor.href);
    }

    whiteSpace = doc.createTextNode(" ");
    composer.selection.setAfter(anchor);
    dom.insert(whiteSpace).after(anchor);
    elementToSetCaretAfter = whiteSpace;
  }
  composer.selection.setAfter(elementToSetCaretAfter);
  return anchors;
}

var createLink = {
  /**
   * TODO: Use HTMLApplier or formatInline here
   *
   * Turns selection into a link
   * If selection is already a link, it removes the link and wraps it with a <code> element
   * The <code> element is needed to avoid auto linking
   *
   * @example
   *    // either ...
   *    wysihtml5.commands.createLink.exec(composer, "createLink", "http://www.google.de");
   *    // ... or ...
   *    wysihtml5.commands.createLink.exec(composer, "createLink", { href: "http://www.google.de", target: "_blank" });
   */
  exec: function(composer, command, value) {
    var anchors = this.state(composer, command);
    if (anchors) {
      // Selection contains links
      composer.selection.executeAndRestore(function() {
        _removeFormat(composer, anchors);
      });
    } else {
      // Create links
      value = typeof(value) === "object" ? value : { href: value };
      return _format(composer, value);
    }
  },

  state: function(composer, command) {
    return formatInline.state(composer, command, "A");
  }
};

export { createLink };
<|endoftext|>


<commit_before>var QuizzCollection = Backbone.Collection.extend({
  model: QuizzModel,
  url: '../data/quizz.json'
});
<commit_msg>Fix url to json<commit_after>var QuizzCollection = Backbone.Collection.extend({
  model: QuizzModel,
  url: './data/quizz.json'
});
<|endoftext|>


<commit_before>/*

The MIT License (MIT)

Copyright (c) 2013 Rémi Arnaud - Advanced Micro Devices, Inc.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.*/
//
setViewer6Upload=function(upload){
    var header;
    var index;
    var buttonToReplace;
    upload.callOnClick(function(){
        header = upload.header();
        index=0;
    });
    var url = '/rest3d/upload',
        uploadButton = $('<button/>')
            .addClass('btn')
            .prop('disabled', true)
            .on('click', function (){
                var $this = $(this),
                    data = $this.data();
                $this
                    .off('click')
                    .on('click', function () {
                        $this.remove();
                        data.abort();
                    });
                data.submit();
                buttonToReplace=$(this);
                //.always(function () {
                //     $this.remove();
                // });
        }),
        // show the name of the file nicely
        formatName = function(data,file){
            var i = file.name.lastIndexOf('/');
            return file.name.substring(i+1);
        },
        convertButton = $('<button/>')
            .addClass('btn')
            .prop('disabled', true)
            .on('click', function () {
                var $this = $(this),
                    data = $this.data();
                $this
                    .off('click')
                    .prop('disabled',true)
                // user rest to convert dae into glTF
                var callback = function(data) {
                    $this.prop('disabled',true);
                    if(data.result.output){console.debug(data.result.output);}
                    if(data.result.code){console.debug("Exit code: "+data.result.code);}
                    if (data.error){
                        var span = $('
Error code='+data.error.code+' :: '+data.error.message+'
');
                        data.context.append(span);
                    } else {
                        // ennumerate all resulting files
                        var $conve = upload.header(data.file.name);
                        $.each(data.result.files, function (index, file) {
                            var href = $('');
                            upload.filesArea.append(href);
                            var $download = $("<button>Download</button>").on("click",function(){
                                href[0].click();
                            });

                        var url = decodeURIComponent(file.url);
                        var ext = url.match(/\.[^.]+$/);
                        if(ext==".json"){
                            var $dialog = $("<button>Launch your model</button>").on("click",function(){
                                glTF.load(url, viewer.parse_gltf);
                                window.notif(url);
                            });
                            var $preview = $("<button>Peview</button>").on("click",function(){
                                var gitHtml = '

';
                                gitPanel = $('body').append(gitHtml);
                                $("#dialog").dialog({
                                    autoOpen: true,
                                    width: 800,
                                    height: 600,
                                    open: function (ev, ui) {
                                        $('#myIframe').attr('src', '/viewer/easy-viewer.html?file=/rest3d/upload/'+decodeURIComponent(file.name));
                                    }
                                });
                            });
                                upload.convert($conve,formatName(data,file),$dialog,$download,$preview);
                        }
                        else{
                            upload.download($conve,formatName(data,file),$download);//
                        }
                        });
                    }
                }

                rest3d.convert(data,callback);
            });

    upload.object.on('fileuploadadd', function (e, data) {
        upload.object=$(this);
        data.context = header;
        $.each(data.files, function (index, file) {
            var ext = file.name.match(/\.[^.]+$/);//
            if(ext=".dae"){
                var url =  '/rest3d/upload/'+decodeURIComponent(file.name);//
                console.debug(url);
                var $dialog = $("<button>Launch your model</button>").on("click",function(){
                                COLLADA.load(url, viewer.parse_dae);
                                window.notif(url);
                            })
                            .prop("id","dialog"+index);
                 var $preview = $("<button>Peview</button>").on("click",function(){
                                var gitHtml = '

';
                                gitPanel = $('body').append(gitHtml);
                                $("#dialog").dialog({
                                    autoOpen: true,
                                    width: 800,
                                    height: 600,
                                    open: function (ev, ui) {
                                        $('#myIframe').attr('src', '/viewer/easy-viewer.html?file=/rest3d/upload/'+decodeURIComponent(file.name));
                                    }//
                                });
                            })
                 .prop("id","preview"+index);
                array = []
                upload.upload(header,file.name,$preview,$dialog,uploadButton.clone(true).data(data));
                console.debug($dialog+" "+$preview);
                $('#dialog'+index).hide();
                $('#preview'+index).hide();
            }
            else{this.upload(header,file.name);}
        });
    }).on('fileuploadprocessalways', function (e, data) {
            var indexI = data.index,
            file = data.files[indexI],
             node = $(data.context.children('div')[index+1]);
        if (file.preview) {
            node
                .prepend('
')
                .prepend(file.preview);
        }
        if (file.error) {
          GUI.addTooltip({
                    parent: node.find('button'),
                    content: file.error,
                });//
        }
        if (indexI + 1 === data.files.length) {
            node.find('button')
                .prop('disabled', !!data.files.error);
        }
        index++;//
    }).on('fileuploadprogressall', function (e, data) {
        var progress = parseInt(data.loaded / data.total * 100, 10);
        upload.progress.setValue(progress);
    }).on('fileuploaddone', function (e, data) {//
        $.each(data.result.files, function (index, file) {
            file.assetName = data.result.files[index].name;
            var $node = convertButton.clone(true).data({file: file, context: data.context})
                .prop('disabled', !/dae$/i.test(file.url))
            buttonToReplace
                .replaceWith($node)
                .prop("id","nodeClose");//
            GUI.addIcon($node, "ui-icon-check", "", "before");
            $node.parent().parent().show().children().show();;
        });
    }).on('fileuploadfail', function (e, data) {
        if (!data.result) {
            $(data.context.children()[0])
                .append('
')
                .append('error communicating with server')
                .find('button').remove();
        } else
        $.each(data.result.files, function (index, file) {
            var error = $('').text(file.error);
            $(data.context.children()[index])
                .append('
')
                .append(error)
                .find('button').remove();
        });
    });
}
<commit_msg>sadldasp<commit_after>/*

The MIT License (MIT)

Copyright (c) 2013 Rémi Arnaud - Advanced Micro Devices, Inc.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.*/
//
setViewer6Upload=function(upload){
    var header;
    var index;
    var buttonToReplace;
    upload.callOnClick(function(){
        header = upload.header();
        index=0;
    });
    var url = '/rest3d/upload',
        uploadButton = $('<button/>')
            .addClass('btn')
            .prop('disabled', true)
            .on('click', function (){
                var $this = $(this),
                    data = $this.data();
                $this
                    .off('click')
                    .on('click', function () {
                        $this.remove();
                        data.abort();
                    });
                data.submit();
                buttonToReplace=$(this);
                //.always(function () {
                //     $this.remove();
                // });
        }),
        // show the name of the file nicely
        formatName = function(data,file){
            var i = file.name.lastIndexOf('/');
            return file.name.substring(i+1);
        },
        convertButton = $('<button/>')
            .addClass('btn')
            .prop('disabled', true)
            .on('click', function () {
                var $this = $(this),
                    data = $this.data();
                $this
                    .off('click')
                    .prop('disabled',true)
                // user rest to convert dae into glTF
                var callback = function(data) {
                    $this.prop('disabled',true);
                    if(data.result.output){console.debug(data.result.output);}
                    if(data.result.code){console.debug("Exit code: "+data.result.code);}
                    if (data.error){
                        var span = $('
Error code='+data.error.code+' :: '+data.error.message+'
');
                        data.context.append(span);
                    } else {
                        // ennumerate all resulting files
                        var $conve = upload.header(data.file.name);
                        $.each(data.result.files, function (index, file) {
                            var href = $('');
                            upload.filesArea.append(href);
                            var $download = $("<button>Download</button>").on("click",function(){
                                href[0].click();
                            });

                        var url = decodeURIComponent(file.url);
                        var ext = url.match(/\.[^.]+$/);
                        if(ext==".json"){
                            var $dialog = $("<button>Launch your model</button>").on("click",function(){
                                glTF.load(url, viewer.parse_gltf);
                                window.notif(url);
                            });
                            var $preview = $("<button>Peview</button>").on("click",function(){
                                var gitHtml = '

';
                                gitPanel = $('body').append(gitHtml);
                                $("#dialog").dialog({
                                    autoOpen: true,
                                    width: 800,
                                    height: 600,
                                    open: function (ev, ui) {
                                        $('#myIframe').attr('src', '/viewer/easy-viewer.html?file=/rest3d/upload/'+decodeURIComponent(file.name));
                                    }
                                });
                            });
                                upload.convert($conve,formatName(data,file),$dialog,$download,$preview);
                        }
                        else{
                            upload.download($conve,formatName(data,file),$download);//
                        }
                        });
                    }
                }

                rest3d.convert(data,callback);
            });

    upload.object.on('fileuploadadd', function (e, data) {
        upload.object=$(this);
        data.context = header;
        $.each(data.files, function (index, file) {
            var ext = file.name.match(/\.[^.]+$/);//
            if(ext=".dae"){
                var url =  '/rest3d/upload/'+decodeURIComponent(file.name);//
                console.debug(url);
                var $dialog = $("<button>Launch your model</button>").on("click",function(){
                                COLLADA.load(url, viewer.parse_dae);
                                window.notif(url);
                            })
                            .prop("id","dialog"+index);
                 var $preview = $("<button>Peview</button>").on("click",function(){
                                var gitHtml = '

';
                                gitPanel = $('body').append(gitHtml);
                                $("#dialog").dialog({
                                    autoOpen: true,
                                    width: 800,
                                    height: 600,
                                    open: function (ev, ui) {
                                        $('#myIframe').attr('src', '/viewer/easy-viewer.html?file=/rest3d/upload/'+decodeURIComponent(file.name));
                                    }//
                                });
                            })
                 .prop("id","preview"+index);
                array = []
                upload.upload(header,file.name,$preview,$dialog,uploadButton.clone(true).data(data));
                console.debug($dialog+" "+$preview);
                $('#dialog'+index).hide();
                $('#preview'+index).hide();
            }
            else{this.upload(header,file.name);}
        });
    }).on('fileuploadprocessalways', function (e, data) {
            var indexI = data.index,
            file = data.files[indexI],
             node = $(data.context.children('div')[index+1]);
        if (file.preview) {
            node
                .prepend('
')
                .prepend(file.preview);//
        }
        if (file.error) {
          GUI.addTooltip({
                    parent: node.find('button'),
                    content: file.error,
                });//
        }
        if (indexI + 1 === data.files.length) {
            node.find('button')
                .prop('disabled', !!data.files.error);
        }
        index++;//
    }).on('fileuploadprogressall', function (e, data) {
        var progress = parseInt(data.loaded / data.total * 100, 10);
        upload.progress.setValue(progress);
    }).on('fileuploaddone', function (e, data) {//
        $.each(data.result.files, function (index, file) {
            file.assetName = data.result.files[index].name;
            var $node = convertButton.clone(true).data({file: file, context: data.context})
                .prop('disabled', !/dae$/i.test(file.url))
            buttonToReplace
                .replaceWith($node)
                .prop("id","nodeClose");//
            GUI.addIcon($node, "ui-icon-check", "", "before");
            $node.parent().parent().show().children().show();;
        });
    }).on('fileuploadfail', function (e, data) {
        if (!data.result) {
            $(data.context.children()[0])
                .append('
')
                .append('error communicating with server')
                .find('button').remove();
        } else
        $.each(data.result.files, function (index, file) {
            var error = $('').text(file.error);
            $(data.context.children()[index])
                .append('
')
                .append(error)
                .find('button').remove();
        });
    });
}
<|endoftext|>


<commit_before>/*!
 * @author:    Divio AG
 * @copyright: http://www.divio.ch
 */

// #############################################################################
// CKEDITOR
/**
 * Default CKEDITOR Styles
 * Added within src/settings.py CKEDITOR_SETTINGS.stylesSet
 *
 * @module CKEDITOR
 */

CKEDITOR.allElements = ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'div'];
CKEDITOR.stylesSet.add('default', [
    /* Block Styles */
    { 'name': 'Text Lead', 'element': CKEDITOR.allElements, 'attributes': { 'class': 'lead' }},

    { 'name': 'Text Left', 'element': CKEDITOR.allElements, 'attributes': { 'class': 'text-left' }},
    { 'name': 'Text Center', 'element': CKEDITOR.allElements, 'attributes': { 'class': 'text-center' }},
    { 'name': 'Text Right', 'element': CKEDITOR.allElements, 'attributes': { 'class': 'text-right' }},
    { 'name': 'Text Justify', 'element': CKEDITOR.allElements, 'attributes': { 'class': 'text-justify' }},
    { 'name': 'Text NoWrap', 'element': CKEDITOR.allElements, 'attributes': { 'class': 'text-nowrap' }},

    { 'name': 'Spacer', 'element': 'div', 'attributes': { 'class': 'spacer' }},
    { 'name': 'Spacer Small', 'element': 'div', 'attributes': { 'class': 'spacer-xs' }},
    { 'name': 'Spacer Large', 'element': 'div', 'attributes': { 'class': 'spacer-lg' }},
    { 'name': 'Spacer Zero', 'element': 'div', 'attributes': { 'class': 'spacer-zero' }},

    { 'name': 'List Unstyled', 'element': ['ul', 'ol'], 'attributes': { 'class': 'list-unstyled' }},
    { 'name': 'List Inline', 'element': ['ul', 'ol'], 'attributes': { 'class': 'list-inline' }},
    { 'name': 'Horizontal Description', 'element': 'dl', 'attributes': { 'class': 'dl-horizontal' }},

    { 'name': 'Table', 'element': 'table', 'attributes': { 'class': 'table' }},
    { 'name': 'Table Responsive', 'element': 'table', 'attributes': { 'class': 'table-responsive' }},
    { 'name': 'Table Striped', 'element': 'table', 'attributes': { 'class': 'table-striped' }},
    { 'name': 'Table Bordered', 'element': 'table', 'attributes': { 'class': 'table-bordered' }},
    { 'name': 'Table Hover', 'element': 'table', 'attributes': { 'class': 'table-hover' }},
    { 'name': 'Table Condensed', 'element': 'table', 'attributes': { 'class': 'table-condensed' }},

    { 'name': 'Table Cell Active', 'element': ['tr', 'th', 'td'], 'attributes': { 'class': 'active' }},
    { 'name': 'Table Cell Success', 'element': ['tr', 'th', 'td'], 'attributes': { 'class': 'success' }},
    { 'name': 'Table Cell Warning', 'element': ['tr', 'th', 'td'], 'attributes': { 'class': 'warning' }},
    { 'name': 'Table Cell Danger', 'element': ['tr', 'th', 'td'], 'attributes': { 'class': 'danger' }},
    { 'name': 'Table Cell Info', 'element': ['tr', 'th', 'td'], 'attributes': { 'class': 'info' }},

    /* Inline Styles */
    { 'name': 'Text Primary', 'element': 'span', 'attributes': { 'class': 'text-primary' }},
    { 'name': 'Text Success', 'element': 'span', 'attributes': { 'class': 'text-success' }},
    { 'name': 'Text Info', 'element': 'span', 'attributes': { 'class': 'text-info' }},
    { 'name': 'Text Warning', 'element': 'span', 'attributes': { 'class': 'text-warning' }},
    { 'name': 'Text Danger', 'element': 'span', 'attributes': { 'class': 'text-danger' }},
    { 'name': 'Text Muted', 'element': 'span', 'attributes': { 'class': 'text-muted' }},

    { 'name': 'Image Responsive', 'element': 'img', 'attributes': { 'class': 'img-responsive' }},
    { 'name': 'Image Rounded', 'element': 'img', 'attributes': { 'class': 'img-rounded' }},
    { 'name': 'Image Circle', 'element': 'img', 'attributes': { 'class': 'img-circle' }},
    { 'name': 'Image Thumbnail', 'element': 'img', 'attributes': { 'class': 'img-thumbnail' }},

    { 'name': 'Pull Left', 'element': CKEDITOR.allElements, 'attributes': { 'class': 'pull-left' }},
    { 'name': 'Pull Right', 'element': CKEDITOR.allElements, 'attributes': { 'class': 'pull-right' }},

    { 'name': 'Blockquote Reverse', 'element': 'blockquote', 'attributes': { 'class': 'blockquote-reverse' }}
]);

/*
 * Extend ckeditor default settings
 * DOCS: http://docs.ckeditor.com/#!/api/CKEDITOR.dtd
 */
CKEDITOR.dtd.$removeEmpty.span = 0;
<commit_msg>add global<commit_after>/*!
 * @author:    Divio AG
 * @copyright: http://www.divio.ch
 */

// #############################################################################
// CKEDITOR
/**
 * Default CKEDITOR Styles
 * Added within src/settings.py CKEDITOR_SETTINGS.stylesSet
 *
 * @module CKEDITOR
 */
/* global CKEDITOR */

CKEDITOR.allElements = ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'div'];
CKEDITOR.stylesSet.add('default', [
    /* Block Styles */
    { 'name': 'Text Lead', 'element': CKEDITOR.allElements, 'attributes': { 'class': 'lead' }},

    { 'name': 'Text Left', 'element': CKEDITOR.allElements, 'attributes': { 'class': 'text-left' }},
    { 'name': 'Text Center', 'element': CKEDITOR.allElements, 'attributes': { 'class': 'text-center' }},
    { 'name': 'Text Right', 'element': CKEDITOR.allElements, 'attributes': { 'class': 'text-right' }},
    { 'name': 'Text Justify', 'element': CKEDITOR.allElements, 'attributes': { 'class': 'text-justify' }},
    { 'name': 'Text NoWrap', 'element': CKEDITOR.allElements, 'attributes': { 'class': 'text-nowrap' }},

    { 'name': 'Spacer', 'element': 'div', 'attributes': { 'class': 'spacer' }},
    { 'name': 'Spacer Small', 'element': 'div', 'attributes': { 'class': 'spacer-xs' }},
    { 'name': 'Spacer Large', 'element': 'div', 'attributes': { 'class': 'spacer-lg' }},
    { 'name': 'Spacer Zero', 'element': 'div', 'attributes': { 'class': 'spacer-zero' }},

    { 'name': 'List Unstyled', 'element': ['ul', 'ol'], 'attributes': { 'class': 'list-unstyled' }},
    { 'name': 'List Inline', 'element': ['ul', 'ol'], 'attributes': { 'class': 'list-inline' }},
    { 'name': 'Horizontal Description', 'element': 'dl', 'attributes': { 'class': 'dl-horizontal' }},

    { 'name': 'Table', 'element': 'table', 'attributes': { 'class': 'table' }},
    { 'name': 'Table Responsive', 'element': 'table', 'attributes': { 'class': 'table-responsive' }},
    { 'name': 'Table Striped', 'element': 'table', 'attributes': { 'class': 'table-striped' }},
    { 'name': 'Table Bordered', 'element': 'table', 'attributes': { 'class': 'table-bordered' }},
    { 'name': 'Table Hover', 'element': 'table', 'attributes': { 'class': 'table-hover' }},
    { 'name': 'Table Condensed', 'element': 'table', 'attributes': { 'class': 'table-condensed' }},

    { 'name': 'Table Cell Active', 'element': ['tr', 'th', 'td'], 'attributes': { 'class': 'active' }},
    { 'name': 'Table Cell Success', 'element': ['tr', 'th', 'td'], 'attributes': { 'class': 'success' }},
    { 'name': 'Table Cell Warning', 'element': ['tr', 'th', 'td'], 'attributes': { 'class': 'warning' }},
    { 'name': 'Table Cell Danger', 'element': ['tr', 'th', 'td'], 'attributes': { 'class': 'danger' }},
    { 'name': 'Table Cell Info', 'element': ['tr', 'th', 'td'], 'attributes': { 'class': 'info' }},

    /* Inline Styles */
    { 'name': 'Text Primary', 'element': 'span', 'attributes': { 'class': 'text-primary' }},
    { 'name': 'Text Success', 'element': 'span', 'attributes': { 'class': 'text-success' }},
    { 'name': 'Text Info', 'element': 'span', 'attributes': { 'class': 'text-info' }},
    { 'name': 'Text Warning', 'element': 'span', 'attributes': { 'class': 'text-warning' }},
    { 'name': 'Text Danger', 'element': 'span', 'attributes': { 'class': 'text-danger' }},
    { 'name': 'Text Muted', 'element': 'span', 'attributes': { 'class': 'text-muted' }},

    { 'name': 'Image Responsive', 'element': 'img', 'attributes': { 'class': 'img-responsive' }},
    { 'name': 'Image Rounded', 'element': 'img', 'attributes': { 'class': 'img-rounded' }},
    { 'name': 'Image Circle', 'element': 'img', 'attributes': { 'class': 'img-circle' }},
    { 'name': 'Image Thumbnail', 'element': 'img', 'attributes': { 'class': 'img-thumbnail' }},

    { 'name': 'Pull Left', 'element': CKEDITOR.allElements, 'attributes': { 'class': 'pull-left' }},
    { 'name': 'Pull Right', 'element': CKEDITOR.allElements, 'attributes': { 'class': 'pull-right' }},

    { 'name': 'Blockquote Reverse', 'element': 'blockquote', 'attributes': { 'class': 'blockquote-reverse' }}
]);

/*
 * Extend ckeditor default settings
 * DOCS: http://docs.ckeditor.com/#!/api/CKEDITOR.dtd
 */
CKEDITOR.dtd.$removeEmpty.span = 0;
<|endoftext|>


<commit_before>// ==UserScript==
// @name        Kurahen Premium
// @namespace   karachan.org
// @description Zestaw dodatkowych opcji dla forum młodzieżowo-katolickiego
// @version     1.0
// @include     http://www.karachan.org/*
// @include     http://karachan.org/*
// @exclude     http://www.karachan.org/*/src/*
// @exclude     http://karachan.org/*/src/*
// ==/UserScript==

(function () {
	'use strict';

	// Konfiguracja
	var customBBoardTitle = '/b/ - Random';
	var enableBetterFonts = true; // Podmienia domyślne czcionki na Roboto

	// Zaawansowana konfiguracja
	var bbCodes = ['b', 'i', 'u', 's', 'small', 'code', 'spoiler'];
	var wordfilters = [
		['#nowocioty', 'STAROCIOTY PAMIĘTAJĄ'],
		['#gimbo', 'xD'],
		['#penis', 'pisiorek'],
		['#wagina', 'cipuszka'],
		['#m__b', 'groźny WYKOPEK wykryty'],
		['#Lasoupeauxchoux', 'kapuśniaczek'],
		['#homoś', 'pedał'],
		['#korwinkrulempolski', 'kongres nowej prawicy'],
		['#1%', 'groźny LEWAK wykryty']
	];
	var boardsWithId = ['b', 'fz', 'z'];
	var colors = [
		'#FF8080',
		'#FFDD80',
		'#80FFB7',
		'#80D0FF',
		'#C680FF',
		'#FFAE80',
		'#D5FF80',
		'#80FFFD',
		'#8097FF',
		'#FF80CA',
		"#ff7f7f",
		"#779aef",
		"#b0de6f",
		"#cc66c0",
		"#5cb9a9",
		"#f3bb79",
		"#8d71e2",
		"#6dd168",
		"#be5f7e",
		"#7bc8f6"
	];

	var KurahenPremium = function () {
		var currentBoardName = this.getCurrentBoardName();

		if (currentBoardName === '') {
			return; // We are not on any useful page
		} else if (currentBoardName === 'b') {
			this.changeBoardTitle(customBBoardTitle);
		}
		this.updatePageTitle();
		this.disableNightStyle();
		this.setCookie('regulamin', 'accepted');
		this.insertButtonBar();
		this.replaceEmailFieldWithSelect();
		this.showAllPostersEmails();
		this.fixAllExternalLinks();

		if (boardsWithId.indexOf(currentBoardName) > -1 && this.isCurrentWebpageThread()) {
			this.colorizeAndNamePosters();
		}

		if (enableBetterFonts) {
			this.changeFonts();
		}
	};

	KurahenPremium.prototype.changeBoardTitle = function (newTitle) {
		document.title = newTitle;
		document.getElementsByClassName('boardTitle')[0].textContent = newTitle;
	};

	KurahenPremium.prototype.updatePageTitle = function () {
		var page = parseInt(window.location.pathname.split('/')[2]);
		var prefix = '';

		if (this.isCurrentWebpageThread()) {
			prefix = this.getTopicFromFirstPostContent();
		} else if (!isNaN(page)) {
			prefix = 'Strona ' + page;
		}

		if (prefix.length > 0) {
			prefix += ' - ';
		}

		document.title = prefix + document.title;
	};

	KurahenPremium.prototype.setCookie = function (name, value) {
		document.cookie = encodeURIComponent(name) + '=' + encodeURIComponent(value) + '; path=/; max-age=2592000';
	};

	KurahenPremium.prototype.changeFonts = function () {
		var newLink = document.createElement('link');
		newLink.href = '//fonts.googleapis.com/css?family=Roboto:400,700&subset=latin,latin-ext';
		newLink.rel = 'stylesheet';
		var existingLink = document.getElementsByTagName('link')[0];
		existingLink.parentNode.insertBefore(newLink, existingLink);
		document.body.style.fontFamily = 'Roboto, "Helvetica Neue", Helvetica, Arial, sans-serif';
	};

	KurahenPremium.prototype.getCurrentBoardName = function () {
		return window.location.pathname.split('/')[1];
	};

	KurahenPremium.prototype.isCurrentWebpageThread = function () {
		return window.location.pathname.split('/')[2] === 'res';
	};

	KurahenPremium.prototype.getTopicFromFirstPostContent = function () {
		var postMessage = document.querySelector('.thread .postMessage').cloneNode(true);

		var backlinks = postMessage.getElementsByClassName('backlink');
		if (backlinks.length > 0) {
			postMessage.removeChild(backlinks[0]);
		}

		var links = postMessage.getElementsByClassName('postlink');
		for (var i = 0; i < links.length; i++) {
			postMessage.removeChild(links[i]);
		}

		var postContent = postMessage.textContent;
		return postContent.substr(0, Math.min(postContent.length, 70));
	};

	KurahenPremium.prototype.disableNightStyle = function () {
		var option = document.querySelector('#stylechanger option[value$="night.css"]');
		option.disabled = true;
	};

	KurahenPremium.prototype.replaceEmailFieldWithSelect = function () {
		var emailField = document.querySelector('#postform input[name="email"]');

		var select = document.createElement('select');
		select.name = 'email';
		select.style.margin = '0';
		select.style.width = '236px';
		select.addEventListener('change', function () {
			//noinspection JSPotentiallyInvalidUsageOfThis
			if (this.options[this.selectedIndex].value === 'custom') {
				var textField = document.createElement('input');
				textField.type = 'text';
				textField.className = 'board-input';
				textField.name = 'email';
				select.parentNode.replaceChild(textField, select);
				textField.focus();
			}
		}, false);

		var optionBump = document.createElement('option');
		optionBump.value = '';
		optionBump.selected = true;
		optionBump.textContent = 'Podbij';
		select.appendChild(optionBump);

		var optionSage = document.createElement('option');
		optionSage.value = 'sage';
		optionSage.textContent = 'Saguj';
		select.appendChild(optionSage);

		var optionSpoiler = document.createElement('option');
		optionSpoiler.value = 'spoiler';
		optionSpoiler.textContent = 'Ukryj obrazek';
		select.appendChild(optionSpoiler);

		var optionCustom = document.createElement('option');
		optionCustom.value = 'custom';
		optionCustom.textContent = 'Wpisz własny...';
		select.appendChild(optionCustom);

		emailField.parentNode.replaceChild(select, emailField);
	};

	KurahenPremium.prototype.showAllPostersEmails = function () {
		var postersEmails = document.getElementsByClassName('useremail');

		for (var i = 0; i < postersEmails.length; i++) {
			postersEmails[i].textContent += ' (' + this.parseMailto(postersEmails[i].getAttribute('href')) + ') ';
			postersEmails[i].removeAttribute('href');
		}
	};

	KurahenPremium.prototype.fixAllExternalLinks = function () {
		var links = document.getElementsByClassName('postlink');
		for (var i = 0; i < links.length; i++) {
			links[i].setAttribute('href', links[i].getAttribute('href').replace('https://href.li/?', ''));
			links[i].setAttribute('target', '_blank');
			links[i].setAttribute('rel', 'noreferrer');
		}
	};

	/**
	 * @private
	 */
	KurahenPremium.prototype.parseMailto = function (mailto) {
		return mailto.replace('mailto:', '');
	};

	KurahenPremium.prototype.colorizeAndNamePosters = function () {
		var postersIds = document.getElementsByClassName("posteruid");
		var postersStats = {};

		var opId;
		for (var i = 0; i < postersIds.length; i++) {
			var posterId = this.parsePosterId(postersIds[i].textContent);
			if (i === 0) {
				opId = posterId;
			}

			postersIds[i].className += ' poster-id-' + posterId;
			if (posterId === opId) {
				postersIds[i].textContent = '\u00a0OP nitki';
			} else {
				postersIds[i].textContent = '\u00a0' + posterId;
			}

			if (isNaN(postersStats[posterId])) {
				postersStats[posterId] = 1;
			} else {
				postersStats[posterId]++;
			}
		}

		var style = document.createElement('style');
		style.type = 'text/css';
		for (var id in postersStats) {
			if (postersStats.hasOwnProperty(id) && postersStats[id] > 1) {
				style.textContent += '.poster-id-' + id + '{color:#000;background-color: ' + this.getNextColor() + ';}';
				style.textContent += '.poster-id-' + id + ':after{content:" (' + postersStats[id] + ' postów)\u00a0"}';
			}
		}
		document.getElementsByTagName('head')[0].appendChild(style);
	};

	/**
	 * @private
	 */
	KurahenPremium.prototype.getNextColor = function () {
		if (colors.length > 0) {
			return colors.shift();
		} else {
			return '#' + Math.random().toString(16).substr(-6); // Random color
		}
	};

	/**
	 * @private
	 */
	KurahenPremium.prototype.parsePosterId = function (text) {
		return text.trim().substr(5, 8).replace(/[\.|\/|\+|\-]/g, '_');
	};

	KurahenPremium.prototype.insertButtonBar = function () {
		var postForm = document.getElementById('postform');
		var textarea = document.querySelector("#postform textarea");
		var buttonBar = document.createElement('div');
		buttonBar.style.textAlign = 'center';

		this.insertTextFormattingButtons(textarea, buttonBar);
		this.insertWordfilterList(textarea, buttonBar);

		postForm.insertBefore(buttonBar, postForm.firstChild);
	};

	/**
	 * @private
	 */
	KurahenPremium.prototype.insertTextFormattingButtons = function (textarea, buttonBar) {
		var onButtonClick = function () {
			var startTag = '[' + this.value + ']';
			var endTag = '[/' + this.value + ']';

			var textBeforeSelection = textarea.value.substring(0, textarea.selectionStart);
			var selectedText = textarea.value.substring(textarea.selectionStart, textarea.selectionEnd);
			var textAfterSelection = textarea.value.substring(textarea.selectionEnd, textarea.value.length);

			textarea.value = textBeforeSelection + startTag + selectedText + endTag + textAfterSelection;

			textarea.focus();
			textarea.selectionStart += startTag.length;
			textarea.selectionEnd = textarea.selectionStart + selectedText.length;
		};

		for (var i = 0; i < bbCodes.length; i++) {
			var button = document.createElement('input');
			button.type = 'button';
			button.value = bbCodes[i];
			button.addEventListener('click', onButtonClick, false);
			buttonBar.appendChild(button);
		}
	};

	/**
	 * @private
	 */
	KurahenPremium.prototype.insertWordfilterList = function (textarea, buttonBar) {
		var wordfiltersSelect = document.createElement('select');

		var defaultOption = document.createElement('option');
		defaultOption.value = '';
		defaultOption.disabled = true;
		defaultOption.selected = true;
		defaultOption.textContent = 'WORDFILTRY';
		wordfiltersSelect.appendChild(defaultOption);

		wordfiltersSelect.addEventListener('change', function () {
			//noinspection JSPotentiallyInvalidUsageOfThis
			var textToInsert = this.options[this.selectedIndex].value;
			var textBeforeEndOfSelection = textarea.value.substring(0, textarea.selectionEnd);
			var textAfterEndOfSelection = textarea.value.substring(textarea.selectionEnd, textarea.value.length);

			textarea.value = textBeforeEndOfSelection + textToInsert + textAfterEndOfSelection;

			textarea.focus();
			textarea.selectionStart = textBeforeEndOfSelection.length + textToInsert.length;
			textarea.selectionEnd = textarea.selectionStart;

			//noinspection JSPotentiallyInvalidUsageOfThis
			this.selectedIndex = 0;
		}, false);

		for (var j = 0; j < wordfilters.length; j++) {
			var option = document.createElement('option');
			option.value = wordfilters[j][0];
			option.textContent = wordfilters[j][1];
			wordfiltersSelect.appendChild(option);
		}

		buttonBar.appendChild(wordfiltersSelect);
	};

	// Initialize script
	window.KurahenPremium = new KurahenPremium();
})();
<commit_msg>Add embedding Youtube and Vocaroo links<commit_after>// ==UserScript==
// @name        Kurahen Premium
// @namespace   karachan.org
// @description Zestaw dodatkowych opcji dla forum młodzieżowo-katolickiego
// @version     1.0
// @include     http://www.karachan.org/*
// @include     http://karachan.org/*
// @exclude     http://www.karachan.org/*/src/*
// @exclude     http://karachan.org/*/src/*
// ==/UserScript==

(function () {
	'use strict';

	// Konfiguracja
	var customBBoardTitle = '/b/ - Random';
	var enableBetterFonts = true; // Podmienia domyślne czcionki na Roboto

	// Zaawansowana konfiguracja
	var bbCodes = ['b', 'i', 'u', 's', 'small', 'code', 'spoiler'];
	var wordfilters = [
		['#nowocioty', 'STAROCIOTY PAMIĘTAJĄ'],
		['#gimbo', 'xD'],
		['#penis', 'pisiorek'],
		['#wagina', 'cipuszka'],
		['#m__b', 'groźny WYKOPEK wykryty'],
		['#Lasoupeauxchoux', 'kapuśniaczek'],
		['#homoś', 'pedał'],
		['#korwinkrulempolski', 'kongres nowej prawicy'],
		['#1%', 'groźny LEWAK wykryty']
	];
	var boardsWithId = ['b', 'fz', 'z'];
	var colors = [
		'#FF8080',
		'#FFDD80',
		'#80FFB7',
		'#80D0FF',
		'#C680FF',
		'#FFAE80',
		'#D5FF80',
		'#80FFFD',
		'#8097FF',
		'#FF80CA',
		"#ff7f7f",
		"#779aef",
		"#b0de6f",
		"#cc66c0",
		"#5cb9a9",
		"#f3bb79",
		"#8d71e2",
		"#6dd168",
		"#be5f7e",
		"#7bc8f6"
	];

	var KurahenPremium = function () {
		var currentBoardName = this.getCurrentBoardName();

		if (currentBoardName === '') {
			return; // We are not on any useful page
		} else if (currentBoardName === 'b') {
			this.changeBoardTitle(customBBoardTitle);
		}
		this.updatePageTitle();
		this.disableNightStyle();
		this.setCookie('regulamin', 'accepted');
		this.insertButtonBar();
		this.replaceEmailFieldWithSelect();
		this.showAllPostersEmails();
		this.fixAllExternalLinks();

		if (boardsWithId.indexOf(currentBoardName) > -1 && this.isCurrentWebpageThread()) {
			this.colorizeAndNamePosters();
		}

		if (enableBetterFonts) {
			this.changeFonts();
		}
	};

	KurahenPremium.prototype.changeBoardTitle = function (newTitle) {
		document.title = newTitle;
		document.getElementsByClassName('boardTitle')[0].textContent = newTitle;
	};

	KurahenPremium.prototype.updatePageTitle = function () {
		var page = parseInt(window.location.pathname.split('/')[2]);
		var prefix = '';

		if (this.isCurrentWebpageThread()) {
			prefix = this.getTopicFromFirstPostContent();
		} else if (!isNaN(page)) {
			prefix = 'Strona ' + page;
		}

		if (prefix.length > 0) {
			prefix += ' - ';
		}

		document.title = prefix + document.title;
	};

	KurahenPremium.prototype.setCookie = function (name, value) {
		document.cookie = encodeURIComponent(name) + '=' + encodeURIComponent(value) + '; path=/; max-age=2592000';
	};

	KurahenPremium.prototype.changeFonts = function () {
		var newLink = document.createElement('link');
		newLink.href = '//fonts.googleapis.com/css?family=Roboto:400,700&subset=latin,latin-ext';
		newLink.rel = 'stylesheet';
		var existingLink = document.getElementsByTagName('link')[0];
		existingLink.parentNode.insertBefore(newLink, existingLink);
		document.body.style.fontFamily = 'Roboto, "Helvetica Neue", Helvetica, Arial, sans-serif';
	};

	KurahenPremium.prototype.getCurrentBoardName = function () {
		return window.location.pathname.split('/')[1];
	};

	KurahenPremium.prototype.isCurrentWebpageThread = function () {
		return window.location.pathname.split('/')[2] === 'res';
	};

	KurahenPremium.prototype.getTopicFromFirstPostContent = function () {
		var postMessage = document.querySelector('.thread .postMessage').cloneNode(true);

		var backlinks = postMessage.getElementsByClassName('backlink');
		if (backlinks.length > 0) {
			postMessage.removeChild(backlinks[0]);
		}

		var links = postMessage.getElementsByClassName('postlink');
		for (var i = 0; i < links.length; i++) {
			postMessage.removeChild(links[i]);
		}

		var postContent = postMessage.textContent;
		return postContent.substr(0, Math.min(postContent.length, 70));
	};

	KurahenPremium.prototype.disableNightStyle = function () {
		var option = document.querySelector('#stylechanger option[value$="night.css"]');
		option.disabled = true;
	};

	KurahenPremium.prototype.replaceEmailFieldWithSelect = function () {
		var emailField = document.querySelector('#postform input[name="email"]');

		var select = document.createElement('select');
		select.name = 'email';
		select.style.margin = '0';
		select.style.width = '236px';
		select.addEventListener('change', function () {
			//noinspection JSPotentiallyInvalidUsageOfThis
			if (this.options[this.selectedIndex].value === 'custom') {
				var textField = document.createElement('input');
				textField.type = 'text';
				textField.className = 'board-input';
				textField.name = 'email';
				select.parentNode.replaceChild(textField, select);
				textField.focus();
			}
		}, false);

		var optionBump = document.createElement('option');
		optionBump.value = '';
		optionBump.selected = true;
		optionBump.textContent = 'Podbij';
		select.appendChild(optionBump);

		var optionSage = document.createElement('option');
		optionSage.value = 'sage';
		optionSage.textContent = 'Saguj';
		select.appendChild(optionSage);

		var optionSpoiler = document.createElement('option');
		optionSpoiler.value = 'spoiler';
		optionSpoiler.textContent = 'Ukryj obrazek';
		select.appendChild(optionSpoiler);

		var optionCustom = document.createElement('option');
		optionCustom.value = 'custom';
		optionCustom.textContent = 'Wpisz własny...';
		select.appendChild(optionCustom);

		emailField.parentNode.replaceChild(select, emailField);
	};

	KurahenPremium.prototype.showAllPostersEmails = function () {
		var postersEmails = document.getElementsByClassName('useremail');

		for (var i = 0; i < postersEmails.length; i++) {
			postersEmails[i].textContent += ' (' + this.parseMailto(postersEmails[i].getAttribute('href')) + ') ';
			postersEmails[i].removeAttribute('href');
		}
	};

	KurahenPremium.prototype.fixAllExternalLinks = function () {
		var links = document.getElementsByClassName('postlink');
		for (var i = 0; i < links.length; i++) {
			links[i].setAttribute('href', links[i].getAttribute('href').replace('https://href.li/?', ''));
			links[i].setAttribute('target', '_blank');
			links[i].setAttribute('rel', 'noreferrer');
		}

		this.inlineVideoAndAudioLinks(links);
	};

	/**
	 * @private
	 */
	KurahenPremium.prototype.parseMailto = function (mailto) {
		return mailto.replace('mailto:', '');
	};

	/**
	 * @private
	 */
	KurahenPremium.prototype.inlineVideoAndAudioLinks = function (links) {
		for (var i = 0; i < links.length; i++) {
			var url = links[i].getAttribute('href');

			if (url.indexOf('youtu') > -1) {
				var urlParameters = url.match(/^.*(?:youtu.be\/|v\/|e\/|u\/\w+\/|embed\/|v=)([^#\&\?]*).*/);
				if (urlParameters === null || urlParameters.length !== 2) {
					continue;
				}

				var youtubeContainer = document.createElement('div');
				youtubeContainer.innerHTML = '<iframe width="560" height="315" src="//www.youtube.com/embed/' +
					urlParameters[1] + '" frameborder="0" allowfullscreen></iframe>';

				if (links[i].nextSibling) {
					links[i].parentNode.insertBefore(youtubeContainer, links[i].nextSibling);
				} else {
					links[i].parentNode.appendChild(youtubeContainer);
				}
				links[i].style.display = 'none';
			} else if (url.indexOf('http://vocaroo.com') > -1) {
				var vocarooId = url.substr(url.length - 12, 12);

				var vocarooContainer = document.createElement('div');
				vocarooContainer.innerHTML = '<embed src="http://vocaroo.com/player.swf?playMediaID=' + vocarooId +
					'&autoplay=0" width="148" height="44" wmode="transparent" type="application/x-shockwave-flash"></embed>';

				if (links[i].nextSibling) {
					links[i].parentNode.insertBefore(vocarooContainer, links[i].nextSibling);
				} else {
					links[i].parentNode.appendChild(vocarooContainer);
				}
				links[i].style.display = 'none';
			}
		}
	};

	KurahenPremium.prototype.colorizeAndNamePosters = function () {
		var postersIds = document.getElementsByClassName("posteruid");
		var postersStats = {};

		var opId;
		for (var i = 0; i < postersIds.length; i++) {
			var posterId = this.parsePosterId(postersIds[i].textContent);
			if (i === 0) {
				opId = posterId;
			}

			postersIds[i].className += ' poster-id-' + posterId;
			if (posterId === opId) {
				postersIds[i].textContent = '\u00a0OP nitki';
			} else {
				postersIds[i].textContent = '\u00a0' + posterId;
			}

			if (isNaN(postersStats[posterId])) {
				postersStats[posterId] = 1;
			} else {
				postersStats[posterId]++;
			}
		}

		var style = document.createElement('style');
		style.type = 'text/css';
		for (var id in postersStats) {
			if (postersStats.hasOwnProperty(id) && postersStats[id] > 1) {
				style.textContent += '.poster-id-' + id + '{color:#000;background-color: ' + this.getNextColor() + ';}';
				style.textContent += '.poster-id-' + id + ':after{content:" (' + postersStats[id] + ' postów)\u00a0"}';
			}
		}
		document.getElementsByTagName('head')[0].appendChild(style);
	};

	/**
	 * @private
	 */
	KurahenPremium.prototype.getNextColor = function () {
		if (colors.length > 0) {
			return colors.shift();
		} else {
			return '#' + Math.random().toString(16).substr(-6); // Random color
		}
	};

	/**
	 * @private
	 */
	KurahenPremium.prototype.parsePosterId = function (text) {
		return text.trim().substr(5, 8).replace(/[\.|\/|\+|\-]/g, '_');
	};

	KurahenPremium.prototype.insertButtonBar = function () {
		var postForm = document.getElementById('postform');
		var textarea = document.querySelector("#postform textarea");
		var buttonBar = document.createElement('div');
		buttonBar.style.textAlign = 'center';

		this.insertTextFormattingButtons(textarea, buttonBar);
		this.insertWordfilterList(textarea, buttonBar);

		postForm.insertBefore(buttonBar, postForm.firstChild);
	};

	/**
	 * @private
	 */
	KurahenPremium.prototype.insertTextFormattingButtons = function (textarea, buttonBar) {
		var onButtonClick = function () {
			var startTag = '[' + this.value + ']';
			var endTag = '[/' + this.value + ']';

			var textBeforeSelection = textarea.value.substring(0, textarea.selectionStart);
			var selectedText = textarea.value.substring(textarea.selectionStart, textarea.selectionEnd);
			var textAfterSelection = textarea.value.substring(textarea.selectionEnd, textarea.value.length);

			textarea.value = textBeforeSelection + startTag + selectedText + endTag + textAfterSelection;

			textarea.focus();
			textarea.selectionStart += startTag.length;
			textarea.selectionEnd = textarea.selectionStart + selectedText.length;
		};

		for (var i = 0; i < bbCodes.length; i++) {
			var button = document.createElement('input');
			button.type = 'button';
			button.value = bbCodes[i];
			button.addEventListener('click', onButtonClick, false);
			buttonBar.appendChild(button);
		}
	};

	/**
	 * @private
	 */
	KurahenPremium.prototype.insertWordfilterList = function (textarea, buttonBar) {
		var wordfiltersSelect = document.createElement('select');

		var defaultOption = document.createElement('option');
		defaultOption.value = '';
		defaultOption.disabled = true;
		defaultOption.selected = true;
		defaultOption.textContent = 'WORDFILTRY';
		wordfiltersSelect.appendChild(defaultOption);

		wordfiltersSelect.addEventListener('change', function () {
			//noinspection JSPotentiallyInvalidUsageOfThis
			var textToInsert = this.options[this.selectedIndex].value;
			var textBeforeEndOfSelection = textarea.value.substring(0, textarea.selectionEnd);
			var textAfterEndOfSelection = textarea.value.substring(textarea.selectionEnd, textarea.value.length);

			textarea.value = textBeforeEndOfSelection + textToInsert + textAfterEndOfSelection;

			textarea.focus();
			textarea.selectionStart = textBeforeEndOfSelection.length + textToInsert.length;
			textarea.selectionEnd = textarea.selectionStart;

			//noinspection JSPotentiallyInvalidUsageOfThis
			this.selectedIndex = 0;
		}, false);

		for (var j = 0; j < wordfilters.length; j++) {
			var option = document.createElement('option');
			option.value = wordfilters[j][0];
			option.textContent = wordfilters[j][1];
			wordfiltersSelect.appendChild(option);
		}

		buttonBar.appendChild(wordfiltersSelect);
	};

	// Initialize script
	window.KurahenPremium = new KurahenPremium();
})();
<|endoftext|>


<commit_before>var tc = tc || {};
tc.gam = tc.gam || {};
tc.gam.project_widgets = tc.gam.project_widgets || {};

tc.gam.project_widgets.need_form = function(options) {
    tc.util.log('project.need_form');
    var dom = options.dom,
        self = {};

    /**
     * Function: initMerlin
     * Initialize the merlin object for validation of the modal dialog.
     */
    var initMerlin = function(need_id) {
        var merlin;

        //We are using merlin only for the built-in validation in this case.
        merlin =  new tc.merlin(options.app, {
            name:'need_form',
            dom:tc.jQ('.add-need.merlin'),
            next_button:tc.jQ('a.need-submit'),
            first_step:'need_form',
            use_hashchange:false,
            data: {
              type:'volunteer',
              request:null,
              quantity:null,
              description:null,
              date:null,
              time:null,
              duration:null,
              project_id:null,
              address:null
            },
            steps: {
                'need_form': {
                    selector: '.step.add-need-step',
                    next_step:'need-submit',
                    inputs: {
                        'quantity': {
                            selector: '#vol-quantity',
                            validators: ['required', 'numeric'],
                            hint:'Qty'
                        },
                        'request': {
                            selector: '#vol-job',
                            validators: ['required', 'max-100'],
                            hint:'Job Title - DJ, Cashier, etc'
                        },
                        'description': {
                          selector: '#vol-desc',
                          validators: ['required', 'max-200'],
                          hint:'Write a brief description of the volunteer tasks and skills.',
                          counter:{
                            selector:'.charlimit.title',
                            limit:200
                          }
                        },
                        'duration': {
                          selector: '#vol-hours',
                          validators: ['required', 'numeric'],
                          hint:''
                        },
                        'address': {
                          selector: '#vol-street',
                          validators: ['required'],
                          hint:'Address'
                        },
                        'month': {
                          selector: '#vol-month',
                          validators: function(input, element, step, submit) {

                            if (submit) {
                              $('.ddSelect').addClass('not-valid has-been-focused has-attempted-submit').removeClass('valid');
                            }

                            if ($(element).val() === 'Month') {
                              $('.ddSelect').addClass('not-valid').removeClass('valid');
                              return {
                                valid: false,
                                errors: ['Must select a month.']
                              }
                            } else {
                              $('.ddSelect').addClass('valid').removeClass('not-valid');
                              return {valid: true}
                            }
                          },
                          hint:'Month'
                        },
                        'day': {
                          selector: '#vol-day',
                          validators: ['required'],
                          hint:'Day'
                        },
                        'time': {
                          selector: '#vol-time',
                          validators: ['required'],
                          hint:'Time'
                        }
                    },
                    init:function(merlin, dom) {
                      // Set up the fancy jqDropDown for month
                      tc.jQ('#vol-month').jqDropDown({
                        toggleBtnName:'ddSelect',
                        optionListName:'ddSelectOptions',
                        containerName:'ddSelectContainer',
                        optionChanged: function() {
                          if ($('#vol-month').val() === 'Month') {
                            $('.ddSelect').addClass('not-valid has-been-focused').removeClass('valid');
                          } else {
                            $('.ddSelect').addClass('valid has-been-focused').removeClass('not-valid');
                          }
                        }
                      });

                      if (need_id) {
                        tc.jQ.each(merlin.current_step.inputs, function(key, input) {
                          if (input.default_val) {
                            input.dom.val(input.default_val);
                          }
                        });
                        merlin.validate(true);
                      }
                    },
                    finish:function(merlin, dom) {
                      var d = new Date();
                      var needDate = d.getFullYear()
                              + '-' + (parseInt(merlin.current_step.inputs.month.dom.val())+1)
                              + '-' + merlin.current_step.inputs.day.dom.val();
                      merlin.options.data = tc.jQ.extend(merlin.options.data,{
                        type:'volunteer',
                        request:merlin.current_step.inputs.request.dom.val(),
                        quantity:merlin.current_step.inputs.quantity.dom.val(),
                        description:merlin.current_step.inputs.description.dom.val(),
                        date:needDate,
                        time:merlin.current_step.inputs.time.dom.val(),
                        duration:merlin.current_step.inputs.duration.dom.val(),
                        project_id:merlin.app.app_page.data.project.project_id,
                        address:merlin.current_step.inputs.address.dom.val()
                      });
                    }
                },
                'need-submit':{
                  selector:'.step.submit-need-step',
                  init:function(merlin,dom){
                    var need_data = merlin.options.data;

                    var success = function(data,tx,xhr){
                      if(data == 'False'){
                        return false;
                      }
                      window.location.hash = 'show,needs';
                      window.location.reload();
                    };
                    if (need_id === undefined) {
                      tc.gam.project_data.createNeed(need_data, success);
                    } else {
                      tc.gam.project_data.updateNeed(need_id, need_data, success);
                    }
                  }
                }
            }
        });

        merlin.show_step('need_form');
    };

    var mergeTemplate = function(need_details) {
        var new_details = tc.jQ.extend(true, {
                day: function() { return this.date ? (new Date(this.date).getUTCDate()) : ''; },
                monthOpts: function() {
                  var needDate = this.date ? (new Date(this.date).getUTCMonth()) : '';
                  var months = ['January','February','March','April','May','June','July','August','September','October','November','December'];
                  var options = '';
                  for (var i = 0; i < months.length; i++) {
                    if (i === needDate) {
                      options += '<option value="' + i + '" selected>' + months[i] + '</option>';
                    } else {
                      options += '<option value="' + i + '">' + months[i] + '</option>';
                    }
                  }
                  return options;
                }
            }, need_details),
            $html = ich.need_form_tmpl(new_details);

        dom.find('.add-need-step').html($html);
    };

    var initForm = function(need_id, callback) {
        if (need_id) {
            tc.gam.project_data.getNeedDetails(need_id, function(data){
                mergeTemplate(data);
                if (callback) {
                    callback();
                }
                initMerlin(need_id);
            });
        } else {
            mergeTemplate();
            if (callback) {
                callback();
            }
            initMerlin();
        }
    };

    /**
     * Function: bindEvents
     * Bind events for this widget
     */
    var bindEvents = function() {
        tc.jQ(tc).bind('show-project-widget', function(event, widgetName, id) {
            if (options.name === widgetName) {
                tc.util.log('&&& showing ' + options.name);

                initForm(id, function(){
                    dom.show();
                });

            } else {
                tc.util.log('&&& hiding ' + options.name);
                dom.hide();
            }
        });
    };

    bindEvents();
    return self;
};
<commit_msg>add numeric validation to the need form date<commit_after>var tc = tc || {};
tc.gam = tc.gam || {};
tc.gam.project_widgets = tc.gam.project_widgets || {};

tc.gam.project_widgets.need_form = function(options) {
    tc.util.log('project.need_form');
    var dom = options.dom,
        self = {};

    /**
     * Function: initMerlin
     * Initialize the merlin object for validation of the modal dialog.
     */
    var initMerlin = function(need_id) {
        var merlin;

        //We are using merlin only for the built-in validation in this case.
        merlin =  new tc.merlin(options.app, {
            name:'need_form',
            dom:tc.jQ('.add-need.merlin'),
            next_button:tc.jQ('a.need-submit'),
            first_step:'need_form',
            use_hashchange:false,
            data: {
              type:'volunteer',
              request:null,
              quantity:null,
              description:null,
              date:null,
              time:null,
              duration:null,
              project_id:null,
              address:null
            },
            steps: {
                'need_form': {
                    selector: '.step.add-need-step',
                    next_step:'need-submit',
                    inputs: {
                        'quantity': {
                            selector: '#vol-quantity',
                            validators: ['required', 'numeric'],
                            hint:'Qty'
                        },
                        'request': {
                            selector: '#vol-job',
                            validators: ['required', 'max-100'],
                            hint:'Job Title - DJ, Cashier, etc'
                        },
                        'description': {
                          selector: '#vol-desc',
                          validators: ['required', 'max-200'],
                          hint:'Write a brief description of the volunteer tasks and skills.',
                          counter:{
                            selector:'.charlimit.title',
                            limit:200
                          }
                        },
                        'duration': {
                          selector: '#vol-hours',
                          validators: ['required', 'numeric'],
                          hint:''
                        },
                        'address': {
                          selector: '#vol-street',
                          validators: ['required'],
                          hint:'Address'
                        },
                        'month': {
                          selector: '#vol-month',
                          validators: function(input, element, step, submit) {

                            if (submit) {
                              $('.ddSelect').addClass('not-valid has-been-focused has-attempted-submit').removeClass('valid');
                            }

                            if ($(element).val() === 'Month') {
                              $('.ddSelect').addClass('not-valid').removeClass('valid');
                              return {
                                valid: false,
                                errors: ['Must select a month.']
                              }
                            } else {
                              $('.ddSelect').addClass('valid').removeClass('not-valid');
                              return {valid: true}
                            }
                          },
                          hint:'Month'
                        },
                        'day': {
                          selector: '#vol-day',
                          validators: ['required', 'numeric'],
                          hint:'Day'
                        },
                        'time': {
                          selector: '#vol-time',
                          validators: ['required'],
                          hint:'Time'
                        }
                    },
                    init:function(merlin, dom) {
                      // Set up the fancy jqDropDown for month
                      tc.jQ('#vol-month').jqDropDown({
                        toggleBtnName:'ddSelect',
                        optionListName:'ddSelectOptions',
                        containerName:'ddSelectContainer',
                        optionChanged: function() {
                          if ($('#vol-month').val() === 'Month') {
                            $('.ddSelect').addClass('not-valid has-been-focused').removeClass('valid');
                          } else {
                            $('.ddSelect').addClass('valid has-been-focused').removeClass('not-valid');
                          }
                        }
                      });

                      if (need_id) {
                        tc.jQ.each(merlin.current_step.inputs, function(key, input) {
                          if (input.default_val) {
                            input.dom.val(input.default_val);
                          }
                        });
                        merlin.validate(true);
                      }
                    },
                    finish:function(merlin, dom) {
                      var d = new Date();
                      var needDate = d.getFullYear()
                              + '-' + (parseInt(merlin.current_step.inputs.month.dom.val())+1)
                              + '-' + merlin.current_step.inputs.day.dom.val();
                      merlin.options.data = tc.jQ.extend(merlin.options.data,{
                        type:'volunteer',
                        request:merlin.current_step.inputs.request.dom.val(),
                        quantity:merlin.current_step.inputs.quantity.dom.val(),
                        description:merlin.current_step.inputs.description.dom.val(),
                        date:needDate,
                        time:merlin.current_step.inputs.time.dom.val(),
                        duration:merlin.current_step.inputs.duration.dom.val(),
                        project_id:merlin.app.app_page.data.project.project_id,
                        address:merlin.current_step.inputs.address.dom.val()
                      });
                    }
                },
                'need-submit':{
                  selector:'.step.submit-need-step',
                  init:function(merlin,dom){
                    var need_data = merlin.options.data;

                    var success = function(data,tx,xhr){
                      if(data == 'False'){
                        return false;
                      }
                      window.location.hash = 'show,needs';
                      window.location.reload();
                    };
                    if (need_id === undefined) {
                      tc.gam.project_data.createNeed(need_data, success);
                    } else {
                      tc.gam.project_data.updateNeed(need_id, need_data, success);
                    }
                  }
                }
            }
        });

        merlin.show_step('need_form');
    };

    var mergeTemplate = function(need_details) {
        var new_details = tc.jQ.extend(true, {
                day: function() { return this.date ? (new Date(this.date).getUTCDate()) : ''; },
                monthOpts: function() {
                  var needDate = this.date ? (new Date(this.date).getUTCMonth()) : '';
                  var months = ['January','February','March','April','May','June','July','August','September','October','November','December'];
                  var options = '';
                  for (var i = 0; i < months.length; i++) {
                    if (i === needDate) {
                      options += '<option value="' + i + '" selected>' + months[i] + '</option>';
                    } else {
                      options += '<option value="' + i + '">' + months[i] + '</option>';
                    }
                  }
                  return options;
                }
            }, need_details),
            $html = ich.need_form_tmpl(new_details);

        dom.find('.add-need-step').html($html);
    };

    var initForm = function(need_id, callback) {
        if (need_id) {
            tc.gam.project_data.getNeedDetails(need_id, function(data){
                mergeTemplate(data);
                if (callback) {
                    callback();
                }
                initMerlin(need_id);
            });
        } else {
            mergeTemplate();
            if (callback) {
                callback();
            }
            initMerlin();
        }
    };

    /**
     * Function: bindEvents
     * Bind events for this widget
     */
    var bindEvents = function() {
        tc.jQ(tc).bind('show-project-widget', function(event, widgetName, id) {
            if (options.name === widgetName) {
                tc.util.log('&&& showing ' + options.name);

                initForm(id, function(){
                    dom.show();
                });

            } else {
                tc.util.log('&&& hiding ' + options.name);
                dom.hide();
            }
        });
    };

    bindEvents();
    return self;
};
<|endoftext|>


<commit_before>import React from 'react';

// Redux
import withRedux from 'next-redux-wrapper';
import { initStore } from 'store';
import { setUser } from 'redactions/user';
import { setRouter } from 'redactions/routes';
import { fetchDashboard } from 'components/dashboards/detail/dashboard-detail-actions';

// Components
import Page from 'components/app/layout/Page';
import Layout from 'components/app/layout/Layout';
import Breadcrumbs from 'components/ui/Breadcrumbs';
import DashboardDetail from 'components/dashboards/detail/dashboard-detail';
import DashboardThumbnailList from 'components/dashboards/thumbnail-list/dashboard-thumbnail-list';
import { fetchDashboards, setSelected, setExpanded, setPagination } from 'components/dashboards/thumbnail-list/dashboard-thumbnail-list-actions';

class DashboardsDetail extends Page {
  static async getInitialProps({ asPath, pathname, query, req, store, isServer }) {
    const { user } = isServer ? req : store.getState();
    const url = { asPath, pathname, query };
    await store.dispatch(setUser(user));
    store.dispatch(setRouter(url));

    await store.dispatch(fetchDashboard({ id: url.query.slug }));

    // We load the list of dashboards if not already done
    store.dispatch(setPagination(true));
    store.dispatch(setSelected(url.query.slug));

    const isDashboardPrivate = store.getState().dashboardDetail.dashboard.published;
    const thumbnailListLoaded = !!store.getState().dashboardThumbnailList.dashboards.length;
    if (isDashboardPrivate && !thumbnailListLoaded) {
      await store.dispatch(fetchDashboards({
        filters: { 'filter[published]': 'true' }
      }));
    }

    return { isServer, user, url };
  }

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

    return (
      <Layout
        title={dashboardDetail.dashboard.name}
        description={dashboardDetail.dashboard.summary}
        url={this.props.url}
        user={this.props.user}
        pageHeader
        className="page-dashboards c-page-dashboards"
      >

                  <Breadcrumbs items={[{ name: 'Dashboards', href: '/data/dashboards' }]} />

{dashboardDetail.dashboard.name}

          {dashboardDetail.dashboard.published && (

                  <DashboardThumbnailList
                    onSelect={({ slug }) => {
                      // We need to make an amendment to have this working
                      // Router.pushRoute('dashboards_detail', { slug });
                      window.location = `/data/dashboards/${slug}`;
                    }}
                    onExpand={(bool) => {
                      this.props.setExpanded(bool);
                    }}
                  />

          )}

                <DashboardDetail />

      </Layout>
    );
  }
}

const mapStateToProps = state => ({
  dashboardDetail: state.dashboardDetail
});

const mapDispatchToProps = {
  fetchDashboard,
  fetchDashboards,
  setSelected,
  setExpanded,
  setPagination
};

export default withRedux(initStore, mapStateToProps, mapDispatchToProps)(DashboardsDetail);
<commit_msg>Remove dashboard thumbnail list from detail page<commit_after>import React from 'react';

// Redux
import withRedux from 'next-redux-wrapper';
import { initStore } from 'store';
import { setUser } from 'redactions/user';
import { setRouter } from 'redactions/routes';
import { fetchDashboard } from 'components/dashboards/detail/dashboard-detail-actions';

// Components
import Page from 'components/app/layout/Page';
import Layout from 'components/app/layout/Layout';
import Breadcrumbs from 'components/ui/Breadcrumbs';
import DashboardDetail from 'components/dashboards/detail/dashboard-detail';

class DashboardsDetail extends Page {
  static async getInitialProps({ asPath, pathname, query, req, store, isServer }) {
    const { user } = isServer ? req : store.getState();
    const url = { asPath, pathname, query };
    await store.dispatch(setUser(user));
    store.dispatch(setRouter(url));

    await store.dispatch(fetchDashboard({ id: url.query.slug }));

    return { isServer, user, url };
  }

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

    return (
      <Layout
        title={dashboardDetail.dashboard.name}
        description={dashboardDetail.dashboard.summary}
        url={this.props.url}
        user={this.props.user}
        pageHeader
        className="page-dashboards c-page-dashboards"
      >

                  <Breadcrumbs items={[{ name: 'Dashboards', href: '/data/dashboards' }]} />

{dashboardDetail.dashboard.name}

                <DashboardDetail />

      </Layout>
    );
  }
}

const mapStateToProps = state => ({
  dashboardDetail: state.dashboardDetail
});

const mapDispatchToProps = {
  fetchDashboard
};

export default withRedux(initStore, mapStateToProps, mapDispatchToProps)(DashboardsDetail);
<|endoftext|>