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

//http://www.quirksmode.org/js/findpos.html
function findPos(obj) {
    var curleft = curtop = 0;
    if (obj.offsetParent) {
        do {
            curleft += obj.offsetLeft;
            curtop += obj.offsetTop;
        } while (obj = obj.offsetParent);
        return [curleft,curtop];
    }
}
var sakai = sakai || {};
sakai.editor = sakai.editor || {};
sakai.editor.editors = sakai.editor.editors || {};
// Temporarily disable enableResourceSearch till citations plugin is ported (SAK-22862)
sakai.editor.enableResourceSearch = false;

sakai.editor.editors.ckeditor = {};
// Please note that no more parameters should be added to this signature.
// The config object allows for name-based config options to be passed.
// The w and h parameters should be removed as soon as their uses can be migrated.
sakai.editor.editors.ckeditor.launch = function(targetId, config, w, h) {
    var folder = "";

    var collectionId = "";
    if (config != null && config.collectionId) {
        collectionId=config.collectionId;
    }
    else if (sakai.editor.collectionId) {
        collectionId=sakai.editor.collectionId
    }

    if (collectionId) {
        folder = "CurrentFolder=" + collectionId
    }

    var language = sakai.locale && sakai.locale.userLanguage || '';
    var country = sakai.locale && sakai.locale.userCountry || null;

    var ckconfig = {
	//Some defaults for audio recorder
        audiorecorder : {
            "maxSeconds" : 180,
            "attemptAllowed" : Number.MAX_VALUE,
            "attemptsRemaining": Number.MAX_VALUE
        },
        skin: 'moono',
        defaultLanguage: 'en',
        allowedContent: true, // http://docs.ckeditor.com/#!/guide/dev_advanced_content_filter-section-3
        language: language + (country ? '-' + country.toLowerCase() : ''),
        height: 310,
        fileConnectorUrl : '/sakai-fck-connector/web/editor/filemanager/browser/default/connectors/jsp/connector' + collectionId + '?' + folder,

        filebrowserBrowseUrl :'/library/editor/FCKeditor/editor/filemanager/browser/default/browser.html?Connector=/sakai-fck-connector/web/editor/filemanager/browser/default/connectors/jsp/connector' + collectionId + '&' + folder,
        filebrowserImageBrowseUrl : '/library/editor/FCKeditor/editor/filemanager/browser/default/browser.html?Type=Image&Connector=/sakai-fck-connector/web/editor/filemanager/browser/default/connectors/jsp/connector' + collectionId + '&' + folder,
        filebrowserFlashBrowseUrl :'/library/editor/FCKeditor/editor/filemanager/browser/default/browser.html?Type=Flash&Connector=/sakai-fck-connector/web/editor/filemanager/browser/default/connectors/jsp/connector' + collectionId + '&' + folder,
				extraPlugins: (sakai.editor.enableResourceSearch ? 'resourcesearch,' : '')+'',

        // These two settings enable the browser's native spell checking and context menus.
        // Control-Right-Click (Windows/Linux) or Command-Right-Click (Mac) on highlighted words
        // will cause the CKEditor menu to be suppressed and display the browser's standard context
        // menu. In some cases (Firefox and Safari, at least), this supplies corrections, suggestions, etc.
        disableNativeSpellChecker: false,
        browserContextMenuOnCtrl: true,

        toolbar_Basic:
        [
            ['Source', '-', 'Bold', 'Italic', 'Link', 'Unlink']
        ],
        toolbar_Full:
        [
            ['Source','-','Templates'],
            // Uncomment the next line and comment the following to enable the default spell checker.
            // Note that it uses spellchecker.net, displays ads and sends content to remote servers without additional setup.
            //['Cut','Copy','Paste','PasteText','PasteFromWord','-','Print', 'SpellChecker', 'Scayt'],
            ['Cut','Copy','Paste','PasteText','PasteFromWord','-','Print'],
            ['Undo','Redo','-','Find','Replace','-','SelectAll','RemoveFormat'],
            ['NumberedList','BulletedList','-','Outdent','Indent','Blockquote','CreateDiv'],
            '/',
            ['Bold','Italic','Underline','Strike','-','Subscript','Superscript'],
						['atd-ckeditor'],
            ['JustifyLeft','JustifyCenter','JustifyRight','JustifyBlock'],
            ['BidiLtr', 'BidiRtl' ],
            ['Link','Unlink','Anchor'],
            (sakai.editor.enableResourceSearch
                ? ['AudioRecorder','ResourceSearch', 'Image','Movie','Flash','Table','HorizontalRule','Smiley','SpecialChar','fmath_formula']
                : ['AudioRecorder','Image','Movie','Flash','Table','HorizontalRule','Smiley','SpecialChar','fmath_formula']),
            '/',
            ['Styles','Format','Font','FontSize'],
            ['TextColor','BGColor'],
            ['Maximize', 'ShowBlocks']
        ],
        toolbar: 'Full',
        resize_dir: 'both',
        //SAK-23418
        pasteFromWordRemoveFontStyles : false,
        pasteFromWordRemoveStyles : false
    };

    //NOTE: The height and width properties are handled discretely here.
    //      The ultimate intent is that the caller-supplied config will simply
    //      overlay the default config. The outstanding question is whether
    //      some properties should disallow override (because of specific setup
    //      here that we would not want duplicated throughout calling code) or
    //      if their override would just be discouraged. We also probably want
    //      some symbolic things like editorSize: 'small', where the supplied
    //      values are interpreted and translated into dimensions, toolbar set,
    //      and anything else relevant. This will allow editor indifference
    //      on the part of tool code, requesting whatever editor be launched
    //      with appropriate settings applied, rather than detecting the editor
    //      and supplying specific values for the desired effect. This set of
    //      "logical" configuration options is yet to be determined.
    if (config) {
        if (config.width) {
            ckconfig.width = config.width;
        } else if (w) {
            ckconfig.width = w;
        }

        if (config.height) {
            ckconfig.height = config.height;
        } else if (h) {
            ckconfig.height = h;
        }

        if (config && config.toolbarSet && ckconfig['toolbar_' + config.toolbarSet]) {
            ckconfig.toolbar = config.toolbarSet;
		}

		if (config.fullPage) {
			ckconfig.fullPage = true;
		}

		if (config.audiorecorder) {
			ckconfig.audiorecorder = config.audiorecorder;
		}

		if (config.disableBrowseServer)
		{
			ckconfig.filebrowserBrowseUrl = null;
			ckconfig.filebrowserImageBrowseUrl = null;
			ckconfig.filebrowserFlashBrowseUrl = null;
			ckconfig.filebrowserLinkBrowseUrl = null;
		}
	}

		//get path of directory ckeditor
		//
		var basePath = CKEDITOR.basePath;
		basePath = basePath.substr(0, basePath.indexOf("ckeditor/"))+"ckextraplugins/";
		//To add extra plugins outside the plugins directory, add them here! (And in the variable)
		(function() {
		   CKEDITOR.plugins.addExternal('movieplayer',basePath+'movieplayer/', 'plugin.js');
		   CKEDITOR.plugins.addExternal('wordcount',basePath+'wordcount/', 'plugin.js');
		   CKEDITOR.plugins.addExternal('fmath_formula',basePath+'fmath_formula/', 'plugin.js');
		   CKEDITOR.plugins.addExternal('audiorecorder',basePath+'audiorecorder/', 'plugin.js');
		   CKEDITOR.plugins.addExternal('image2',basePath+'image2/', 'plugin.js');
			 /*
			  To enable after the deadline uncomment these two lines and add atd-ckeditor to toolbar
			  and to extraPlugins. This also needs extra stylesheets.
			  See readme for more info http://www.polishmywriting.com/atd-ckeditor/readme.html
			  You have to actually setup a server or get an API key
			  Hopefully this will get easier to configure soon.
			 */
			 CKEDITOR.plugins.addExternal('atd-ckeditor',basePath+'atd-ckeditor/', 'plugin.js');
			 /*
			 Replace this with your own server if you download it from http://openatd.wordpress.com/
			 Or you can proxy to the public one, see the page for more information.
			 */
			 //ckconfig.atd_rpc='//localhost/proxy/spellcheck';
			 //ckconfig.extraPlugins+="atd-ckeditor,";
			 //ckconfig.contentsCss = basePath+'/atd-ckeditor/atd.css';

			 ckconfig.extraPlugins+="image2,audiorecorder,movieplayer,wordcount,fmath_formula";
    })();

	  CKEDITOR.replace(targetId, ckconfig);
      //SAK-22505
      CKEDITOR.on('dialogDefinition', function(e) {
          // Take the dialog name and its definition from the event
          // data.
          var dialogName = e.data.name;
          var dialogDefinition = e.data.definition;

          var onShow = dialogDefinition.onShow;
          dialogDefinition.onShow = function() {
              var pos = findPos(e.editor.container.$);
              this.move(this.getPosition().x, pos[1]);
              if (typeof onShow !== 'undefined' && typeof onShow.call === 'function') {
                  var result = onShow.call(this);
                  return result;
              }
          }

          if ( dialogName == 'link' )
          {
              var targetTab = dialogDefinition.getContents('target');
              var linkTypeItems = targetTab.elements[0].children[0].items;
              var itemsNoPopup = [];
              for (i=0;i<linkTypeItems.length;i++) {
                  if (linkTypeItems[i][1] != "popup") {
                      itemsNoPopup.push(linkTypeItems[i]);
                  }
              }
              targetTab.elements[0].children[0].items = itemsNoPopup;

          }

      });
}

sakai.editor.launch = sakai.editor.editors.ckeditor.launch;

<commit_msg>SAK-22495 Update config to add autosave plugin<commit_after>/*******************************************************************************
 * $URL:  $
 * $Id:  $
 * **********************************************************************************
 *
 * Copyright (c) 2010 The Sakai Foundation
 *
 * Licensed under the Educational Community License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.opensource.org/licenses/ECL-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ******************************************************************************/

//http://www.quirksmode.org/js/findpos.html
function findPos(obj) {
    var curleft = curtop = 0;
    if (obj.offsetParent) {
        do {
            curleft += obj.offsetLeft;
            curtop += obj.offsetTop;
        } while (obj = obj.offsetParent);
        return [curleft,curtop];
    }
}
var sakai = sakai || {};
sakai.editor = sakai.editor || {};
sakai.editor.editors = sakai.editor.editors || {};
// Temporarily disable enableResourceSearch till citations plugin is ported (SAK-22862)
sakai.editor.enableResourceSearch = false;

sakai.editor.editors.ckeditor = {};
// Please note that no more parameters should be added to this signature.
// The config object allows for name-based config options to be passed.
// The w and h parameters should be removed as soon as their uses can be migrated.
sakai.editor.editors.ckeditor.launch = function(targetId, config, w, h) {
    var folder = "";

    var collectionId = "";
    if (config != null && config.collectionId) {
        collectionId=config.collectionId;
    }
    else if (sakai.editor.collectionId) {
        collectionId=sakai.editor.collectionId
    }

    if (collectionId) {
        folder = "CurrentFolder=" + collectionId
    }

    var language = sakai.locale && sakai.locale.userLanguage || '';
    var country = sakai.locale && sakai.locale.userCountry || null;

    var ckconfig = {
	//Some defaults for audio recorder
        audiorecorder : {
            "maxSeconds" : 180,
            "attemptAllowed" : Number.MAX_VALUE,
            "attemptsRemaining": Number.MAX_VALUE
        },
        skin: 'moono',
        defaultLanguage: 'en',
        allowedContent: true, // http://docs.ckeditor.com/#!/guide/dev_advanced_content_filter-section-3
        language: language + (country ? '-' + country.toLowerCase() : ''),
        height: 310,
        fileConnectorUrl : '/sakai-fck-connector/web/editor/filemanager/browser/default/connectors/jsp/connector' + collectionId + '?' + folder,

        filebrowserBrowseUrl :'/library/editor/FCKeditor/editor/filemanager/browser/default/browser.html?Connector=/sakai-fck-connector/web/editor/filemanager/browser/default/connectors/jsp/connector' + collectionId + '&' + folder,
        filebrowserImageBrowseUrl : '/library/editor/FCKeditor/editor/filemanager/browser/default/browser.html?Type=Image&Connector=/sakai-fck-connector/web/editor/filemanager/browser/default/connectors/jsp/connector' + collectionId + '&' + folder,
        filebrowserFlashBrowseUrl :'/library/editor/FCKeditor/editor/filemanager/browser/default/browser.html?Type=Flash&Connector=/sakai-fck-connector/web/editor/filemanager/browser/default/connectors/jsp/connector' + collectionId + '&' + folder,
				extraPlugins: (sakai.editor.enableResourceSearch ? 'resourcesearch,' : '')+'',

        // These two settings enable the browser's native spell checking and context menus.
        // Control-Right-Click (Windows/Linux) or Command-Right-Click (Mac) on highlighted words
        // will cause the CKEditor menu to be suppressed and display the browser's standard context
        // menu. In some cases (Firefox and Safari, at least), this supplies corrections, suggestions, etc.
        disableNativeSpellChecker: false,
        browserContextMenuOnCtrl: true,

        toolbar_Basic:
        [
            ['Source', '-', 'Bold', 'Italic', 'Link', 'Unlink']
        ],
        toolbar_Full:
        [
            ['Source','-','Templates'],
            // Uncomment the next line and comment the following to enable the default spell checker.
            // Note that it uses spellchecker.net, displays ads and sends content to remote servers without additional setup.
            //['Cut','Copy','Paste','PasteText','PasteFromWord','-','Print', 'SpellChecker', 'Scayt'],
            ['Cut','Copy','Paste','PasteText','PasteFromWord','-','Print'],
            ['Undo','Redo','-','Find','Replace','-','SelectAll','RemoveFormat'],
            ['NumberedList','BulletedList','-','Outdent','Indent','Blockquote','CreateDiv'],
            '/',
            ['Bold','Italic','Underline','Strike','-','Subscript','Superscript'],
						['atd-ckeditor'],
            ['JustifyLeft','JustifyCenter','JustifyRight','JustifyBlock'],
            ['BidiLtr', 'BidiRtl' ],
            ['Link','Unlink','Anchor'],
            (sakai.editor.enableResourceSearch
                ? ['AudioRecorder','ResourceSearch', 'Image','Movie','Flash','Table','HorizontalRule','Smiley','SpecialChar','fmath_formula']
                : ['AudioRecorder','Image','Movie','Flash','Table','HorizontalRule','Smiley','SpecialChar','fmath_formula']),
            '/',
            ['Styles','Format','Font','FontSize'],
            ['TextColor','BGColor'],
            ['Maximize', 'ShowBlocks']
        ],
        toolbar: 'Full',
        resize_dir: 'both',
        //SAK-23418
        pasteFromWordRemoveFontStyles : false,
        pasteFromWordRemoveStyles : false,
        autosave_saveDetectionSelectors : "input[id*='save'],input[name*='save'],input[name*='cancel'],input[id*='cancel']"
    };

    //NOTE: The height and width properties are handled discretely here.
    //      The ultimate intent is that the caller-supplied config will simply
    //      overlay the default config. The outstanding question is whether
    //      some properties should disallow override (because of specific setup
    //      here that we would not want duplicated throughout calling code) or
    //      if their override would just be discouraged. We also probably want
    //      some symbolic things like editorSize: 'small', where the supplied
    //      values are interpreted and translated into dimensions, toolbar set,
    //      and anything else relevant. This will allow editor indifference
    //      on the part of tool code, requesting whatever editor be launched
    //      with appropriate settings applied, rather than detecting the editor
    //      and supplying specific values for the desired effect. This set of
    //      "logical" configuration options is yet to be determined.
    if (config) {
        if (config.width) {
            ckconfig.width = config.width;
        } else if (w) {
            ckconfig.width = w;
        }

        if (config.height) {
            ckconfig.height = config.height;
        } else if (h) {
            ckconfig.height = h;
        }

        if (config && config.toolbarSet && ckconfig['toolbar_' + config.toolbarSet]) {
            ckconfig.toolbar = config.toolbarSet;
		}

		if (config.fullPage) {
			ckconfig.fullPage = true;
		}

		if (config.audiorecorder) {
			ckconfig.audiorecorder = config.audiorecorder;
		}

		if (config.disableBrowseServer)
		{
			ckconfig.filebrowserBrowseUrl = null;
			ckconfig.filebrowserImageBrowseUrl = null;
			ckconfig.filebrowserFlashBrowseUrl = null;
			ckconfig.filebrowserLinkBrowseUrl = null;
		}
	}

		//get path of directory ckeditor
		//
		var basePath = CKEDITOR.basePath;
		basePath = basePath.substr(0, basePath.indexOf("ckeditor/"))+"ckextraplugins/";
		//To add extra plugins outside the plugins directory, add them here! (And in the variable)
		(function() {
		   CKEDITOR.plugins.addExternal('movieplayer',basePath+'movieplayer/', 'plugin.js');
		   CKEDITOR.plugins.addExternal('wordcount',basePath+'wordcount/', 'plugin.js');
		   CKEDITOR.plugins.addExternal('fmath_formula',basePath+'fmath_formula/', 'plugin.js');
		   CKEDITOR.plugins.addExternal('audiorecorder',basePath+'audiorecorder/', 'plugin.js');
		   CKEDITOR.plugins.addExternal('image2',basePath+'image2/', 'plugin.js');
		   CKEDITOR.plugins.addExternal('autosave',basePath+'autosave/', 'plugin.js');
			 /*
			  To enable after the deadline uncomment these two lines and add atd-ckeditor to toolbar
			  and to extraPlugins. This also needs extra stylesheets.
			  See readme for more info http://www.polishmywriting.com/atd-ckeditor/readme.html
			  You have to actually setup a server or get an API key
			  Hopefully this will get easier to configure soon.
			 */
			 CKEDITOR.plugins.addExternal('atd-ckeditor',basePath+'atd-ckeditor/', 'plugin.js');
			 /*
			 Replace this with your own server if you download it from http://openatd.wordpress.com/
			 Or you can proxy to the public one, see the page for more information.
			 */
			 //ckconfig.atd_rpc='//localhost/proxy/spellcheck';
			 //ckconfig.extraPlugins+="atd-ckeditor,";
			 //ckconfig.contentsCss = basePath+'/atd-ckeditor/atd.css';

			 ckconfig.extraPlugins+="image2,audiorecorder,movieplayer,wordcount,fmath_formula,autosave";
    })();

	  CKEDITOR.replace(targetId, ckconfig);
      //SAK-22505
      CKEDITOR.on('dialogDefinition', function(e) {
          // Take the dialog name and its definition from the event
          // data.
          var dialogName = e.data.name;
          var dialogDefinition = e.data.definition;

          var onShow = dialogDefinition.onShow;
          dialogDefinition.onShow = function() {
              var pos = findPos(e.editor.container.$);
              this.move(this.getPosition().x, pos[1]);
              if (typeof onShow !== 'undefined' && typeof onShow.call === 'function') {
                  var result = onShow.call(this);
                  return result;
              }
          }

          if ( dialogName == 'link' )
          {
              var targetTab = dialogDefinition.getContents('target');
              var linkTypeItems = targetTab.elements[0].children[0].items;
              var itemsNoPopup = [];
              for (i=0;i<linkTypeItems.length;i++) {
                  if (linkTypeItems[i][1] != "popup") {
                      itemsNoPopup.push(linkTypeItems[i]);
                  }
              }
              targetTab.elements[0].children[0].items = itemsNoPopup;

          }

      });
}

sakai.editor.launch = sakai.editor.editors.ckeditor.launch;

<|endoftext|>


<commit_before>var ko = require("knockout");
var $ = require("jquery");

// hack to make typeahead work because it expects a global
if (window && !window.jQuery) {
	window.jQuery = $;
}

require("typeahead.js");
require("./typeahead.less");

ko.bindingHandlers.typeahead = {
	update: function (element, valueAccessor, allBindings) {
		// http://stackoverflow.com/a/19366003/1247130 get value to update properly when typeahead choice is selected.

		var templateName = ko.unwrap(allBindings().templateName);
		var mapping = ko.unwrap(allBindings().mappingFunction);
		var onSelect = allBindings.get("onSelectFunction");
		var displayedProperty = ko.unwrap(allBindings().displayKey);
		var value = allBindings.get("value");

		var url = ko.unwrap(valueAccessor());
		var remoteFilter = ko.unwrap(allBindings.get("remoteFilter"));
		var auth = (allBindings.has("authToken")) ? {
			"Authorization": "Bearer " + ko.unwrap(allBindings().authToken)
		} : {};
		var remoteData = {
			url: url,
			ajax: {
				headers: auth
			}
		};
		if (remoteFilter) {
			remoteData.filter = remoteFilter;
		};

		var resultsLimit = allBindings.get("limit") || 10;

		var suggestions = new Bloodhound({
			datumTokenizer: function (token) {
				return Bloodhound.tokenizers.whitespace(token);
			},
			queryTokenizer: Bloodhound.tokenizers.whitespace,
			remote: remoteData,
			limit: resultsLimit
		});

		suggestions.initialize();

		$(element).typeahead("destroy");

		var typeaheadOpts = {
			source: suggestions.ttAdapter(),
			displayKey: displayedProperty || function (item) {
				return item;
			}
		};

		if (templateName) {
			typeaheadOpts.templates = {
				suggestion: function (item) {
					var temp = document.createElement("div");
					var model = mapping ? mapping(item) : item;
					ko.renderTemplate(templateName, model, null, temp, "replaceChildren");

					return temp;
				}
			};
		}

		$(element)
			.typeahead({
				hint: true,
				highlight: true
			}, typeaheadOpts)
		.on("typeahead:selected typeahead:autocompleted", function (e, suggestion) {
			if (onSelect) {
				onSelect(value, suggestion, e)
			}else if (value && ko.isObservable(value)) {
				value(suggestion);
			}
		});
	}
};
<commit_msg>Can now add options to typeahead.<commit_after>var ko = require("knockout");
var $ = require("jquery");

// hack to make typeahead work because it expects a global
if (window && !window.jQuery) {
	window.jQuery = $;
}

require("typeahead.js");
require("./typeahead.less");

ko.bindingHandlers.typeahead = {
	update: function (element, valueAccessor, allBindings) {
		// http://stackoverflow.com/a/19366003/1247130 get value to update properly when typeahead choice is selected.

		var templateName = ko.unwrap(allBindings().templateName);
		var mapping = ko.unwrap(allBindings().mappingFunction);
		var onSelect = allBindings.get("onSelectFunction");
		var displayedProperty = ko.unwrap(allBindings().displayKey);
		var user_typeahead_options = ko.unwrap(allBindings().typeaheadOpts) || {};
		var value = allBindings.get("value");

		var url = ko.unwrap(valueAccessor());
		var remoteFilter = ko.unwrap(allBindings.get("remoteFilter"));
		var auth = (allBindings.has("authToken")) ? {
			"Authorization": "Bearer " + ko.unwrap(allBindings().authToken)
		} : {};
		var remoteData = {
			url: url,
			ajax: {
				headers: auth
			}
		};
		if (remoteFilter) {
			remoteData.filter = remoteFilter;
		};

		var resultsLimit = allBindings.get("limit") || 10;

		var suggestions = new Bloodhound({
			datumTokenizer: function (token) {
				return Bloodhound.tokenizers.whitespace(token);
			},
			queryTokenizer: Bloodhound.tokenizers.whitespace,
			remote: remoteData,
			limit: resultsLimit
		});

		suggestions.initialize();

		$(element).typeahead("destroy");

		var typeaheadOpts = {
			source: suggestions.ttAdapter(),
			displayKey: displayedProperty || function (item) {
				return item;
			}
		};

		if (templateName) {
			typeaheadOpts.templates = {
				suggestion: function (item) {
					var temp = document.createElement("div");
					var model = mapping ? mapping(item) : item;
					ko.renderTemplate(templateName, model, null, temp, "replaceChildren");

					return temp;
				}
			};
		}

		$(element)
			.typeahead(jQuery.extend({
				hint: true,
				highlight: true,
			}, user_typeahead_options), typeaheadOpts)
		.on("typeahead:selected typeahead:autocompleted", function (e, suggestion) {
			if (onSelect) {
				onSelect(value, suggestion, e)
			}else if (value && ko.isObservable(value)) {
				value(suggestion);
			}
		});
	}
};
<|endoftext|>


<commit_before>describe('About Expects', function() {

  // We shall contemplate truth by testing reality, via spec expectations.
  it('should expect true', function() {

    // Your journey begins here: Replace the word false with true
    expect(true).toBeTruthy();
  });

  // To understand reality, we must compare our expectations against reality.
  it('should expect equality', function() {
    var expectedValue = 2;
    var actualValue = 1 + 1;

    expect(actualValue === expectedValue).toBeTruthy();
  });

  // Some ways of asserting equality are better than others.
  it('should assert equality a better way', function() {
    var expectedValue = FILL_ME_IN;
    var actualValue = FILL_ME_IN;

  // toEqual() compares using common sense equality.
    expect(actualValue).toEqual(expectedValue);
  });

  // Sometimes you need to be precise about what you "type."
  it('should assert equality with ===', function() {
    var expectedValue = FILL_ME_IN;
    var actualValue = "Fill this value in";

  // toBe() will always use === to compare.
    expect(actualValue).toBe(expectedValue);
  });

  // Sometimes we will ask you to fill in the values.
  it('should have filled in values', function() {
    expect(1 + 1).toEqual(FILL_ME_IN);
  });
});
<commit_msg>it should have filled in values<commit_after>describe('About Expects', function() {

  // We shall contemplate truth by testing reality, via spec expectations.
  it('should expect true', function() {

    // Your journey begins here: Replace the word false with true
    expect(true).toBeTruthy();
  });

  // To understand reality, we must compare our expectations against reality.
  it('should expect equality', function() {
    var expectedValue = 2;
    var actualValue = 1 + 1;

    expect(actualValue === expectedValue).toBeTruthy();
  });

  // Some ways of asserting equality are better than others.
  it('should assert equality a better way', function() {
    var expectedValue = FILL_ME_IN;
    var actualValue = FILL_ME_IN;

  // toEqual() compares using common sense equality.
    expect(actualValue).toEqual(expectedValue);
  });

  // Sometimes you need to be precise about what you "type."
  it('should assert equality with ===', function() {
    var expectedValue = FILL_ME_IN;
    var actualValue = "Fill this value in";

  // toBe() will always use === to compare.
    expect(actualValue).toBe(expectedValue);
  });

  // Sometimes we will ask you to fill in the values.
  it('should have filled in values', function() {
    expect('Fill this value in').toEqual(FILL_ME_IN);
  });
});
<|endoftext|>


<commit_before>/**
 * @package info.ajaxplorer.plugins
 *
 * Copyright 2007-2009 Charles du Jeu
 * This file is part of AjaXplorer.
 * The latest code can be found at http://www.ajaxplorer.info/
 *
 * This program is published under the LGPL Gnu Lesser General Public License.
 * You should have received a copy of the license along with AjaXplorer.
 *
 * The main conditions are as follow :
 * You must conspicuously and appropriately publish on each copy distributed
 * an appropriate copyright notice and disclaimer of warranty and keep intact
 * all the notices that refer to this License and to the absence of any warranty;
 * and give any other recipients of the Program a copy of the GNU Lesser General
 * Public License along with the Program.
 *
 * If you modify your copy or copies of the library or any portion of it, you may
 * distribute the resulting library provided you do so under the GNU Lesser
 * General Public License. However, programs that link to the library may be
 * licensed under terms of your choice, so long as the library itself can be changed.
 * Any translation of the GNU Lesser General Public License must be accompanied by the
 * GNU Lesser General Public License.
 *
 * If you copy or distribute the program, you must accompany it with the complete
 * corresponding machine-readable source code or with a written offer, valid for at
 * least three years, to furnish the complete corresponding machine-readable source code.
 *
 * Any of the above conditions can be waived if you get permission from the copyright holder.
 * AjaXplorer is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 * Description : The "online edition" manager, encapsulate the CodePress highlighter for some extensions.
 */
Class.create("AjxpCkEditor", TextEditor, {

	initialize: function($super, oFormObject)
	{
		$super(oFormObject);
		this.editorConfig = {
			resize_enabled:false,
			toolbar : "Ajxp",
			filebrowserBrowseUrl : 'index.php?external_selector_type=ckeditor',
			// IF YOU KNOW THE RELATIVE PATH OF THE IMAGES (BETWEEN REPOSITORY ROOT AND REAL FILE)
			// YOU CAN PASS IT WITH THE relative_path PARAMETER. FOR EXAMPLE :
			//filebrowserBrowseUrl : 'index.php?external_selector_type=ckeditor&relative_path=files',
			filebrowserImageBrowseUrl : 'index.php?external_selector_type=ckeditor',
			filebrowserFlashBrowseUrl : 'index.php?external_selector_type=ckeditor',
			language : ajaxplorer.currentLanguage,
			fullPage : true,
			toolbar_Ajxp : [
				['Source','Preview','Templates'],
			    ['Undo','Redo','-', 'Cut','Copy','Paste','PasteText','PasteFromWord','-','Print', 'SpellChecker', 'Scayt'],
			    ['Find','Replace','-','SelectAll','RemoveFormat'],
			    ['Form', 'Checkbox', 'Radio', 'TextField', 'Textarea', 'Select', 'Button', 'ImageButton', 'HiddenField'],
			    '/',
			    ['Bold','Italic','Underline','Strike','-','Subscript','Superscript'],
			    ['NumberedList','BulletedList','-','Outdent','Indent','Blockquote'],
			    ['JustifyLeft','JustifyCenter','JustifyRight','JustifyBlock'],
			    ['Link','Unlink','Anchor'],
			    ['Image','Flash','Table','HorizontalRule','Smiley','SpecialChar','PageBreak'],
			    '/',
			    ['Styles','Format','Font','FontSize'],
			    ['TextColor','BGColor'],
			    ['Maximize', 'ShowBlocks','-','About']
			]

		};
	},

	open : function($super, userSelection){
		this.userSelection = userSelection;
		var fileName = userSelection.getUniqueFileName();
		var textarea;
		this.textareaContainer = new Element('div');
		this.textarea = new Element('textarea');
		this.textarea.name =  this.textarea.id = 'content';
		this.contentMainContainer = this.textareaContainer;
		this.textarea.setStyle({width:'100%'});
		this.textarea.setAttribute('wrap', 'off');
		this.element.insert(this.textareaContainer);
		this.textareaContainer.appendChild(this.textarea);
		fitHeightToBottom(this.textareaContainer, $(modal.elementName));
		this.reloadEditor('content');
		this.element.observe("editor:close", function(){
			CKEDITOR.instances.content.destroy();
		});
		this.element.observe("editor:resize", function(event){
			this.resizeEditor();
		}.bind(this));
		var destroy = function(){
			if(CKEDITOR.instances.content){
				this.textarea.value = CKEDITOR.instances.content.getData();
				CKEDITOR.instances.content.destroy();
			}
		};
		var reInit  = function(){
			CKEDITOR.replace('content', this.editorConfig);
			window.setTimeout(function(){
				this.resizeEditor();
				this.bindCkEditorEvents();
			}.bind(this), 100);
		}
		this.element.observe("editor:enterFS", destroy.bind(this));
		this.element.observe("editor:enterFSend", reInit.bind(this));
		this.element.observe("editor:exitFS", destroy.bind(this));
		this.element.observe("editor:exitFSend", reInit.bind(this));
		// LOAD FILE NOW
		window.setTimeout(this.resizeEditor.bind(this), 400);
		this.loadFileContent(fileName);
		this.bindCkEditorEvents();
		return;

	},

	bindCkEditorEvents : function(){
		if(this.isModified) return;// useless

		window.setTimeout(function(){
			var editor = CKEDITOR.instances.content;
			if(!editor) {
				console.log("not found");
				return;
			}
			var setModified = function(){this.setModified(true)}.bind(this);
			var keyDown = function(event){
	 			if ( !event.data.$.ctrlKey && !event.data.$.metaKey )
	 					this.setModified(true);
	 		}.bind(this);
			// We'll save snapshots before and after executing a command.
	 		editor.on( 'afterCommandExec', setModified );
	 		// Save snapshots before doing custom changes.
	 		editor.on( 'saveSnapshot', setModified );
	 		// Registering keydown on every document recreation.(#3844)
	 		editor.on( 'contentDom', function(e)
	 		{
	 			if(!e.editor.document) return;
	 			e.editor.document.on( 'keydown', keyDown);
	 		});
	 		if(editor.document){
	 			editor.document.on('keydown', keyDown);
	 		}
		}.bind(this), 0);
	},

	reloadEditor : function(instanceId){
		if(!instanceId) instanceId = "code";
		if(CKEDITOR.instances[instanceId]){
			this.textarea.value = CKEDITOR.instances[instanceId].getData();
			CKEDITOR.instances[instanceId].destroy();
		}
		CKEDITOR.replace(instanceId, this.editorConfig);
	},

	resizeEditor : function(){
		var width = this.contentMainContainer.getWidth()-(Prototype.Browser.IE?0:12);
		var height = this.contentMainContainer.getHeight();
		if(CKEDITOR.instances.content){
			CKEDITOR.instances.content.resize(width,height);
		}
	},

	saveFile : function(){
		var connexion = this.prepareSaveConnexion();
		var value = CKEDITOR.instances.content.getData();
		this.textarea.value = value;
		connexion.addParameter('content', value);
		connexion.sendAsync();
	},

	parseTxt : function(transport){
		this.textarea.value = transport.responseText;
		CKEDITOR.instances.content.setData(transport.responseText);
		this.removeOnLoad(this.textareaContainer);
		this.setModified(false);
	}

});<commit_msg>forgotten console.log<commit_after>/**
 * @package info.ajaxplorer.plugins
 *
 * Copyright 2007-2009 Charles du Jeu
 * This file is part of AjaXplorer.
 * The latest code can be found at http://www.ajaxplorer.info/
 *
 * This program is published under the LGPL Gnu Lesser General Public License.
 * You should have received a copy of the license along with AjaXplorer.
 *
 * The main conditions are as follow :
 * You must conspicuously and appropriately publish on each copy distributed
 * an appropriate copyright notice and disclaimer of warranty and keep intact
 * all the notices that refer to this License and to the absence of any warranty;
 * and give any other recipients of the Program a copy of the GNU Lesser General
 * Public License along with the Program.
 *
 * If you modify your copy or copies of the library or any portion of it, you may
 * distribute the resulting library provided you do so under the GNU Lesser
 * General Public License. However, programs that link to the library may be
 * licensed under terms of your choice, so long as the library itself can be changed.
 * Any translation of the GNU Lesser General Public License must be accompanied by the
 * GNU Lesser General Public License.
 *
 * If you copy or distribute the program, you must accompany it with the complete
 * corresponding machine-readable source code or with a written offer, valid for at
 * least three years, to furnish the complete corresponding machine-readable source code.
 *
 * Any of the above conditions can be waived if you get permission from the copyright holder.
 * AjaXplorer is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 * Description : The "online edition" manager, encapsulate the CodePress highlighter for some extensions.
 */
Class.create("AjxpCkEditor", TextEditor, {

	initialize: function($super, oFormObject)
	{
		$super(oFormObject);
		this.editorConfig = {
			resize_enabled:false,
			toolbar : "Ajxp",
			filebrowserBrowseUrl : 'index.php?external_selector_type=ckeditor',
			// IF YOU KNOW THE RELATIVE PATH OF THE IMAGES (BETWEEN REPOSITORY ROOT AND REAL FILE)
			// YOU CAN PASS IT WITH THE relative_path PARAMETER. FOR EXAMPLE :
			//filebrowserBrowseUrl : 'index.php?external_selector_type=ckeditor&relative_path=files',
			filebrowserImageBrowseUrl : 'index.php?external_selector_type=ckeditor',
			filebrowserFlashBrowseUrl : 'index.php?external_selector_type=ckeditor',
			language : ajaxplorer.currentLanguage,
			fullPage : true,
			toolbar_Ajxp : [
				['Source','Preview','Templates'],
			    ['Undo','Redo','-', 'Cut','Copy','Paste','PasteText','PasteFromWord','-','Print', 'SpellChecker', 'Scayt'],
			    ['Find','Replace','-','SelectAll','RemoveFormat'],
			    ['Form', 'Checkbox', 'Radio', 'TextField', 'Textarea', 'Select', 'Button', 'ImageButton', 'HiddenField'],
			    '/',
			    ['Bold','Italic','Underline','Strike','-','Subscript','Superscript'],
			    ['NumberedList','BulletedList','-','Outdent','Indent','Blockquote'],
			    ['JustifyLeft','JustifyCenter','JustifyRight','JustifyBlock'],
			    ['Link','Unlink','Anchor'],
			    ['Image','Flash','Table','HorizontalRule','Smiley','SpecialChar','PageBreak'],
			    '/',
			    ['Styles','Format','Font','FontSize'],
			    ['TextColor','BGColor'],
			    ['Maximize', 'ShowBlocks','-','About']
			]

		};
	},

	open : function($super, userSelection){
		this.userSelection = userSelection;
		var fileName = userSelection.getUniqueFileName();
		var textarea;
		this.textareaContainer = new Element('div');
		this.textarea = new Element('textarea');
		this.textarea.name =  this.textarea.id = 'content';
		this.contentMainContainer = this.textareaContainer;
		this.textarea.setStyle({width:'100%'});
		this.textarea.setAttribute('wrap', 'off');
		this.element.insert(this.textareaContainer);
		this.textareaContainer.appendChild(this.textarea);
		fitHeightToBottom(this.textareaContainer, $(modal.elementName));
		this.reloadEditor('content');
		this.element.observe("editor:close", function(){
			CKEDITOR.instances.content.destroy();
		});
		this.element.observe("editor:resize", function(event){
			this.resizeEditor();
		}.bind(this));
		var destroy = function(){
			if(CKEDITOR.instances.content){
				this.textarea.value = CKEDITOR.instances.content.getData();
				CKEDITOR.instances.content.destroy();
			}
		};
		var reInit  = function(){
			CKEDITOR.replace('content', this.editorConfig);
			window.setTimeout(function(){
				this.resizeEditor();
				this.bindCkEditorEvents();
			}.bind(this), 100);
		}
		this.element.observe("editor:enterFS", destroy.bind(this));
		this.element.observe("editor:enterFSend", reInit.bind(this));
		this.element.observe("editor:exitFS", destroy.bind(this));
		this.element.observe("editor:exitFSend", reInit.bind(this));
		// LOAD FILE NOW
		window.setTimeout(this.resizeEditor.bind(this), 400);
		this.loadFileContent(fileName);
		this.bindCkEditorEvents();
		return;

	},

	bindCkEditorEvents : function(){
		if(this.isModified) return;// useless

		window.setTimeout(function(){
			var editor = CKEDITOR.instances.content;
			if(!editor) {
				return;
			}
			var setModified = function(){this.setModified(true)}.bind(this);
			var keyDown = function(event){
	 			if ( !event.data.$.ctrlKey && !event.data.$.metaKey )
	 					this.setModified(true);
	 		}.bind(this);
			// We'll save snapshots before and after executing a command.
	 		editor.on( 'afterCommandExec', setModified );
	 		// Save snapshots before doing custom changes.
	 		editor.on( 'saveSnapshot', setModified );
	 		// Registering keydown on every document recreation.(#3844)
	 		editor.on( 'contentDom', function(e)
	 		{
	 			if(!e.editor.document) return;
	 			e.editor.document.on( 'keydown', keyDown);
	 		});
	 		if(editor.document){
	 			editor.document.on('keydown', keyDown);
	 		}
		}.bind(this), 0);
	},

	reloadEditor : function(instanceId){
		if(!instanceId) instanceId = "code";
		if(CKEDITOR.instances[instanceId]){
			this.textarea.value = CKEDITOR.instances[instanceId].getData();
			CKEDITOR.instances[instanceId].destroy();
		}
		CKEDITOR.replace(instanceId, this.editorConfig);
	},

	resizeEditor : function(){
		var width = this.contentMainContainer.getWidth()-(Prototype.Browser.IE?0:12);
		var height = this.contentMainContainer.getHeight();
		if(CKEDITOR.instances.content){
			CKEDITOR.instances.content.resize(width,height);
		}
	},

	saveFile : function(){
		var connexion = this.prepareSaveConnexion();
		var value = CKEDITOR.instances.content.getData();
		this.textarea.value = value;
		connexion.addParameter('content', value);
		connexion.sendAsync();
	},

	parseTxt : function(transport){
		this.textarea.value = transport.responseText;
		CKEDITOR.instances.content.setData(transport.responseText);
		this.removeOnLoad(this.textareaContainer);
		this.setModified(false);
	}

});<|endoftext|>


<commit_before>describe("About Expects", function() {

  //We shall contemplate truth by testing reality, via spec expectations.
  it("should expect true", function() {
    expect(true).toBeTruthy(); //This should be true
  });

  //To understand reality, we must compare our expectations against reality.
  it("should expect equality", function () {
	  var expectedValue = 2;
	  var actualValue = 2;

	  expect(actualValue === expectedValue).toBeTruthy();
  });

  //Some ways of asserting equality are better than others.
  it("should assert equality a better way", function () {
	  var expectedValue = FILL_ME_IN;
	  var actualValue = 1 + 1;

  // toEqual() compares using common sense equality.
	  expect(actualValue).toEqual(expectedValue);
  });

  //Sometimes you need to be really exact about what you "type".
  it("should assert equality with ===", function () {
	  var expectedValue = FILL_ME_IN;
	  var actualValue = (1 + 1).toString();

  // toBe() will always use === to compare.
	  expect(actualValue).toBe(expectedValue);
  });

  //Sometimes we will ask you to fill in the values.
  it("should have filled in values", function () {
	  expect(1 + 1).toEqual(FILL_ME_IN);
  });
});
<commit_msg>Update AboutExpects.js<commit_after>describe("About Expects", function() {

  //We shall contemplate truth by testing reality, via spec expectations.
  it("should expect true", function() {
    expect(true).toBeTruthy(); //This should be true
  });

  //To understand reality, we must compare our expectations against reality.
  it("should expect equality", function () {
	  var expectedValue = 1 + 1;
	  var actualValue = 1 + 1;

	  expect(actualValue === expectedValue).toBeTruthy();
  });

  //Some ways of asserting equality are better than others.
  it("should assert equality a better way", function () {
	  var expectedValue = FILL_ME_IN;
	  var actualValue = 1 + 1;

  // toEqual() compares using common sense equality.
	  expect(actualValue).toEqual(expectedValue);
  });

  //Sometimes you need to be really exact about what you "type".
  it("should assert equality with ===", function () {
	  var expectedValue = FILL_ME_IN;
	  var actualValue = (1 + 1).toString();

  // toBe() will always use === to compare.
	  expect(actualValue).toBe(expectedValue);
  });

  //Sometimes we will ask you to fill in the values.
  it("should have filled in values", function () {
	  expect(1 + 1).toEqual(FILL_ME_IN);
  });
});
<|endoftext|>


<commit_before>import { configure, addDecorator } from '@storybook/react'
import centered from '@storybook/addon-centered'

import '~/__utils__/setup'

// settings
addDecorator(centered)

// load
const req = require.context('../', true, /stories.jsx?$/)

function loadStories() {
  req.keys().forEach(filename => req(filename))
}

configure(loadStories, module)
<commit_msg>diff storybook search regex<commit_after>import { configure, addDecorator } from "@storybook/react";
import centered from "@storybook/addon-centered";

import "~/__utils__/setup";

// settings
addDecorator(centered);

// load
const req = require.context("../", true, /stories\.jsx?$/);

function loadStories() {
  req.keys().forEach(filename => req(filename));
}

configure(loadStories, module);
<|endoftext|>


<commit_before>describe("About Objects", function () {

  describe("Properties", function () {
    var meglomaniac;

    beforeEach(function () {
       meglomaniac = {  mastermind: "Joker", henchwoman: "Harley" };
    });

    it("should confirm objects are collections of properties", function () {
      expect(meglomaniac.mastermind).toBe("Joker");
    });

    it("should confirm that properties are case sensitive", function () {
      expect(meglomaniac.henchwoman).toBe("Harley");
      expect(meglomaniac.henchWoman).toBe(undefined);
    });
  });

  it("should know properties that are functions act like methods", function () {
    var meglomaniac = {
      mastermind : "Brain",
      henchman: "Pinky",
      battleCry: function (noOfBrains) {
        return "They are " + this.henchman + " and the" +
          Array(noOfBrains + 1).join(" " + this.mastermind);
      }
    };

    var battleCry = meglomaniac.battleCry(4);
    expect(FILL_ME_IN).toMatch(battleCry);
  });

  it("should confirm that when a function is attached to an object, 'this' refers to the object", function () {
    var currentDate = new Date()
    var currentYear = (currentDate.getFullYear());
    var meglomaniac = {
      mastermind: "James Wood",
      henchman: "Adam West",
      birthYear: 1970,
      calculateAge: function () {
        return currentYear - this.birthYear;
      }
    };

    expect(currentYear).toBe(FILL_ME_IN);
    expect(meglomaniac.calculateAge()).toBe(FILL_ME_IN);
  });

  describe("'in' keyword", function () {
    var meglomaniac;
    beforeEach(function () {
      meglomaniac = {
        mastermind: "The Monarch",
        henchwoman: "Dr Girlfriend",
        theBomb: true
      };
    });

    it("should have the bomb", function () {

      var hasBomb = "theBomb" in meglomaniac;

      expect(hasBomb).toBe(FILL_ME_IN);
    });

    it("should not have the detonator however", function () {

      var hasDetonator = "theDetonator" in meglomaniac;

      expect(hasDetonator).toBe(FILL_ME_IN);
    });
  });

  it("should know that properties can be added and deleted", function () {
    var meglomaniac = { mastermind : "Agent Smith", henchman: "Agent Smith" };

    expect("secretary" in meglomaniac).toBe(FILL_ME_IN);

    meglomaniac.secretary = "Agent Smith";
    expect("secretary" in meglomaniac).toBe(FILL_ME_IN);

    delete meglomaniac.henchman;
    expect("henchman" in meglomaniac).toBe(FILL_ME_IN);
  });

  it("should use prototype to add to all objects", function () {
    function Circle(radius)
    {
      this.radius = radius;
    }

    var simpleCircle = new Circle(10);
    var colouredCircle = new Circle(5);
    colouredCircle.colour = "red";

    expect(simpleCircle.colour).toBe(FILL_ME_IN);
    expect(colouredCircle.colour).toBe(FILL_ME_IN);

    Circle.prototype.describe = function () {
      return "This circle has a radius of: " + this.radius;
    };

    expect(simpleCircle.describe()).toBe(FILL_ME_IN);
    expect(colouredCircle.describe()).toBe(FILL_ME_IN);
  });
});
<commit_msg>When functions take the place of properties within an object they are termed methods, but act the same.<commit_after>describe("About Objects", function () {

  describe("Properties", function () {
    var meglomaniac;

    beforeEach(function () {
       meglomaniac = {  mastermind: "Joker", henchwoman: "Harley" };
    });

    it("should confirm objects are collections of properties", function () {
      expect(meglomaniac.mastermind).toBe("Joker");
    });

    it("should confirm that properties are case sensitive", function () {
      expect(meglomaniac.henchwoman).toBe("Harley");
      expect(meglomaniac.henchWoman).toBe(undefined);
    });
  });

  it("should know properties that are functions act like methods", function () {
    var meglomaniac = {
      mastermind : "Brain",
      henchman: "Pinky",
      battleCry: function (noOfBrains) {
        return "They are " + this.henchman + " and the" +
          Array(noOfBrains + 1).join(" " + this.mastermind);
      }
    };

    var battleCry = meglomaniac.battleCry(4);
    expect("They are Pinky and the Brain Brain Brain Brain Brain").toMatch(battleCry);
  });

  it("should confirm that when a function is attached to an object, 'this' refers to the object", function () {
    var currentDate = new Date()
    var currentYear = (currentDate.getFullYear());
    var meglomaniac = {
      mastermind: "James Wood",
      henchman: "Adam West",
      birthYear: 1970,
      calculateAge: function () {
        return currentYear - this.birthYear;
      }
    };

    expect(currentYear).toBe(FILL_ME_IN);
    expect(meglomaniac.calculateAge()).toBe(FILL_ME_IN);
  });

  describe("'in' keyword", function () {
    var meglomaniac;
    beforeEach(function () {
      meglomaniac = {
        mastermind: "The Monarch",
        henchwoman: "Dr Girlfriend",
        theBomb: true
      };
    });

    it("should have the bomb", function () {

      var hasBomb = "theBomb" in meglomaniac;

      expect(hasBomb).toBe(FILL_ME_IN);
    });

    it("should not have the detonator however", function () {

      var hasDetonator = "theDetonator" in meglomaniac;

      expect(hasDetonator).toBe(FILL_ME_IN);
    });
  });

  it("should know that properties can be added and deleted", function () {
    var meglomaniac = { mastermind : "Agent Smith", henchman: "Agent Smith" };

    expect("secretary" in meglomaniac).toBe(FILL_ME_IN);

    meglomaniac.secretary = "Agent Smith";
    expect("secretary" in meglomaniac).toBe(FILL_ME_IN);

    delete meglomaniac.henchman;
    expect("henchman" in meglomaniac).toBe(FILL_ME_IN);
  });

  it("should use prototype to add to all objects", function () {
    function Circle(radius)
    {
      this.radius = radius;
    }

    var simpleCircle = new Circle(10);
    var colouredCircle = new Circle(5);
    colouredCircle.colour = "red";

    expect(simpleCircle.colour).toBe(FILL_ME_IN);
    expect(colouredCircle.colour).toBe(FILL_ME_IN);

    Circle.prototype.describe = function () {
      return "This circle has a radius of: " + this.radius;
    };

    expect(simpleCircle.describe()).toBe(FILL_ME_IN);
    expect(colouredCircle.describe()).toBe(FILL_ME_IN);
  });
});
<|endoftext|>


<commit_before>describe("About Objects", function () {

  describe("Properties", function () {
    var meglomaniac;

    beforeEach(function () {
       meglomaniac = {  mastermind: "Joker", henchwoman: "Harley" };
    });

    it("should confirm objects are collections of properties", function () {
      expect(meglomaniac.mastermind).toBe(FILL_ME_IN);
    });

    it("should confirm that properties are case sensitive", function () {
      expect(meglomaniac.henchwoman).toBe(FILL_ME_IN);
      expect(meglomaniac.henchWoman).toBe(FILL_ME_IN);
    });
  });

  it("should know properties that are functions act like methods", function () {
    var meglomaniac = {
      mastermind : "Brain",
      henchman: "Pinky",
      battleCry: function (noOfBrains) {
        return "They are " + this.henchman + " and the" +
          Array(noOfBrains + 1).join(" " + this.mastermind);
      }
    };

    var battleCry = meglomaniac.battleCry(4);
    expect(FILL_ME_IN).toMatch(battleCry);
  });

  it("should confirm that when a function is attached to an object, 'this' refers to the object", function () {
    var currentDate = new Date()
    var currentYear = (currentDate.getFullYear());
    var meglomaniac = {
      mastermind: "James Wood",
      henchman: "Adam West",
      birthYear: 1970,
      calculateAge: function () {
        return currentYear - this.birthYear;
      }
    };

    expect(currentYear).toBe(FILL_ME_IN);
    expect(meglomaniac.calculateAge()).toBe(FILL_ME_IN);
  });

  describe("'in' keyword", function () {
    var meglomaniac;
    beforeEach(function () {
      meglomaniac = {
        mastermind: "The Monarch",
        henchwoman: "Dr Girlfriend",
        theBomb: true
      };
    });

    it("should have the bomb", function () {

      var hasBomb = "theBomb" in meglomaniac;

      expect(hasBomb).toBe(FILL_ME_IN);
    });

    it("should not have the detonator however", function () {

      var hasDetonator = "theDetonator" in meglomaniac;

      expect(hasDetonator).toBe(FILL_ME_IN);
    });
  });

  it("should know that properties can be added and deleted", function () {
    var meglomaniac = { mastermind : "Agent Smith", henchman: "Agent Smith" };

    expect("secretary" in meglomaniac).toBe(FILL_ME_IN);

    meglomaniac.secretary = "Agent Smith";
    expect("secretary" in meglomaniac).toBe(FILL_ME_IN);

    delete meglomaniac.henchman;
    expect("henchman" in meglomaniac).toBe(FILL_ME_IN);
  });

  it("should use prototype to add to all objects", function () {
    function Circle(radius)
    {
      this.radius = radius;
    }

    var simpleCircle = new Circle(10);
    var colouredCircle = new Circle(5);
    colouredCircle.colour = "red";

    expect(simpleCircle.colour).toBe(FILL_ME_IN);
    expect(colouredCircle.colour).toBe(FILL_ME_IN);

    Circle.prototype.describe = function () {
      return "This circle has a radius of: " + this.radius;
    };

    expect(simpleCircle.describe()).toBe(FILL_ME_IN);
    expect(colouredCircle.describe()).toBe(FILL_ME_IN);
  });
});
<commit_msg>Completed AboutObjects<commit_after>describe("About Objects", function () {

  describe("Properties", function () {
    var meglomaniac;

    beforeEach(function () {
       meglomaniac = {  mastermind: "Joker", henchwoman: "Harley" };
    });

    it("should confirm objects are collections of properties", function () {
      expect(meglomaniac.mastermind).toBe('Joker');
    });

    it("should confirm that properties are case sensitive", function () {
      expect(meglomaniac.henchwoman).toBe('Harley');
      expect(meglomaniac.henchWoman).toBe(undefined);
    });
  });

  it("should know properties that are functions act like methods", function () {
    var meglomaniac = {
      mastermind : "Brain",
      henchman: "Pinky",
      battleCry: function (noOfBrains) {
        return "They are " + this.henchman + " and the" +
          Array(noOfBrains + 1).join(" " + this.mastermind);
      }
    };

    var battleCry = meglomaniac.battleCry(4);
    expect('They are Pinky and the Brain Brain Brain Brain').toMatch(battleCry);
  });

  it("should confirm that when a function is attached to an object, 'this' refers to the object", function () {
    var currentDate = new Date()
    var currentYear = (currentDate.getFullYear());
    var meglomaniac = {
      mastermind: "James Wood",
      henchman: "Adam West",
      birthYear: 1970,
      calculateAge: function () {
        return currentYear - this.birthYear;
      }
    };

    expect(currentYear).toBe(2014);
    expect(meglomaniac.calculateAge()).toBe(44);
  });

  describe("'in' keyword", function () {
    var meglomaniac;
    beforeEach(function () {
      meglomaniac = {
        mastermind: "The Monarch",
        henchwoman: "Dr Girlfriend",
        theBomb: true
      };
    });

    it("should have the bomb", function () {

      var hasBomb = "theBomb" in meglomaniac;

      expect(hasBomb).toBe(true);
    });

    it("should not have the detonator however", function () {

      var hasDetonator = "theDetonator" in meglomaniac;

      expect(hasDetonator).toBe(false);
    });
  });

  it("should know that properties can be added and deleted", function () {
    var meglomaniac = { mastermind : "Agent Smith", henchman: "Agent Smith" };

    expect("secretary" in meglomaniac).toBe(false);

    meglomaniac.secretary = "Agent Smith";
    expect("secretary" in meglomaniac).toBe(true);

    delete meglomaniac.henchman;
    expect("henchman" in meglomaniac).toBe(false);
  });

  it("should use prototype to add to all objects", function () {
    function Circle(radius)
    {
      this.radius = radius;
    }

    var simpleCircle = new Circle(10);
    var colouredCircle = new Circle(5);
    colouredCircle.colour = "red";

    expect(simpleCircle.colour).toBe(undefined);
    expect(colouredCircle.colour).toBe('red');

    Circle.prototype.describe = function () {
      return "This circle has a radius of: " + this.radius;
    };

    expect(simpleCircle.describe()).toBe('This circle has a radius of: 10');
    expect(colouredCircle.describe()).toBe('This circle has a radius of: 5');
  });
});
<|endoftext|>


<commit_before>describe("build", function() {
  var build = require("../index");
  var fs = require("fs-extra");

  global.test.blog();

  // Only serve a test image when query contains valid user and password
  global.test.server(function(server) {
    server.get("/small.jpg", function(req, res) {
      if (req.query && req.query.user === "x" && req.query.pass === "y")
        res.sendFile(__dirname + "/small.jpg");
      else res.sendStatus(400);
    });

    server.get("/public.jpg", function(req, res) {
      res.sendFile(__dirname + "/small.jpg");
    });
  });

  it("handles image URLs with query strings", function(done) {
    // The test server defined above will only respond with an image if
    // the query string is preserved. I was running into an ampersand
    // encoding issue where the & was replaced with &
    var contents = "";
    var path = "/hello.txt";

    fs.outputFileSync(this.blogDirectory + path, contents);

    build(this.blog, path, {}, function(err, entry) {
      if (err) return done.fail(err);

      // verify the image was cached
      expect(entry.html).toContain("/_image_cache/");

      // verify a thumbnail was generated from the image
      expect(entry.thumbnail.small).toEqual(
        jasmine.objectContaining({
          name: "small.jpg"
        })
      );
      done();
    });
  });

  it("resolves relative paths inside files", function(done) {
    var path = "/blog/foo.txt";
    var contents = "![Image](_foo.jpg)";
    var absolutePathToImage = "/blog/_foo.jpg";

    fs.outputFileSync(this.blogDirectory + path, contents);

    build(this.blog, path, {}, function(err, entry) {
      if (err) return done.fail(err);

      // It won't be cached since the image doesn't exist
      expect(entry.html).toContain(absolutePathToImage);
      done();
    });
  });

  it("generates a blog post from an image with quotes in its filename", function(done) {
    var pathToImage = '/Hello "john" World.jpg';

    fs.copySync(__dirname + "/small.jpg", this.blogDirectory + pathToImage);

    build(this.blog, pathToImage, {}, function(err, entry) {
      if (err) return done.fail(err);

      // verify the image was cached
      expect(entry.html).toContain("/_image_cache/");

      // verify a thumbnail was generated from the image
      expect(entry.thumbnail.small).toEqual(
        jasmine.objectContaining({
          name: "small.jpg"
        })
      );

      done();
    });
  });

  it("handles images with accents and spaces in their filename", function(done) {
    var path = "/blog/Hello world.txt";
    var contents = "![Best Image Ever](óå g.jpg)";
    var pathToImage = "/blog/óå g.jpg";

    fs.outputFileSync(this.blogDirectory + path, contents);
    fs.copySync(__dirname + "/small.jpg", this.blogDirectory + pathToImage);

    build(this.blog, path, {}, function(err, entry) {
      if (err) return done.fail(err);

      // verify the image was cached
      expect(entry.html).toContain("/_image_cache/");

      // verify a thumbnail was generated from the image
      expect(entry.thumbnail.small).toEqual(
        jasmine.objectContaining({
          name: "small.jpg"
        })
      );

      done();
    });
  });

  it("will not use as image to become a thumbnail if it is too small", function(done) {
    var path = "/Hello world.txt";
    var contents = "![Best Image Ever](test.jpg)";
    var pathToImage = "/test.jpg";

    fs.outputFileSync(this.blogDirectory + path, contents);
    fs.copySync(__dirname + "/too-small.jpg", this.blogDirectory + pathToImage);

    build(this.blog, path, {}, function(err, entry) {
      if (err) return done.fail(err);

      // verify no thumbnail was generated from the image
      expect(entry.thumbnail).toEqual({});
      done();
    });
  });

  it("will not include caption text in summaries", function(done) {
    var path = "/Hello world.txt";
    var contents = "# Hello\n\n![Image caption](file.jpg)\n\nWorld";

    fs.outputFileSync(this.blogDirectory + path, contents);

    let blog = this.blog;
    blog.plugins.imageCaption.enabled = true;

    build(blog, path, {}, function(err, entry) {
      if (err) return done.fail(err);

      // verify a thumbnail was generated from the image
      expect(entry.summary).toEqual("World");

      done();
    });
  });

  it("will not generate a publish dateStamp for files without a date in their metadata or path", function(done) {
    var path = "/No-date-in-this-path.txt";
    var contents = "No date in this file";

    fs.outputFileSync(this.blogDirectory + path, contents);
    build(this.blog, path, {}, function(err, entry) {
      if (err) return done.fail(err);
      expect(entry.dateStamp).toEqual(undefined);
      done();
    });
  });

  it("will not cache image an image using the static query string", function(done) {
    var path = "/Hello world.txt";
    var contents = "";

    // we use an img tag instead of a markdown image because for
    // some reason the version of Pandoc running on Blot's CI server
    // creates <embed>'s instead of  for certain URLs
    fs.outputFileSync(this.blogDirectory + path, contents);

    build(this.blog, path, {}, function(err, entry) {
      if (err) return done.fail(err);

      // verify the image was not cached
      expect(entry.html).not.toContain("/_image_cache/");

      // verify a thumbnail was still generated from the image
      expect(entry.thumbnail.small).toEqual(
        jasmine.objectContaining({
          name: "small.jpg"
        })
      );

      done();
    });
  });
});
<commit_msg>Further tweak to new test case<commit_after>describe("build", function() {
  var build = require("../index");
  var fs = require("fs-extra");

  global.test.blog();

  // Only serve a test image when query contains valid user and password
  global.test.server(function(server) {
    server.get("/small.jpg", function(req, res) {
      if (req.query && req.query.user === "x" && req.query.pass === "y")
        res.sendFile(__dirname + "/small.jpg");
      else res.sendStatus(400);
    });

    server.get("/public.jpg", function(req, res) {
      res.sendFile(__dirname + "/small.jpg");
    });
  });

  it("handles image URLs with query strings", function(done) {
    // The test server defined above will only respond with an image if
    // the query string is preserved. I was running into an ampersand
    // encoding issue where the & was replaced with &
    var contents = "";
    var path = "/hello.txt";

    fs.outputFileSync(this.blogDirectory + path, contents);

    build(this.blog, path, {}, function(err, entry) {
      if (err) return done.fail(err);

      // verify the image was cached
      expect(entry.html).toContain("/_image_cache/");

      // verify a thumbnail was generated from the image
      expect(entry.thumbnail.small).toEqual(
        jasmine.objectContaining({
          name: "small.jpg"
        })
      );
      done();
    });
  });

  it("resolves relative paths inside files", function(done) {
    var path = "/blog/foo.txt";
    var contents = "![Image](_foo.jpg)";
    var absolutePathToImage = "/blog/_foo.jpg";

    fs.outputFileSync(this.blogDirectory + path, contents);

    build(this.blog, path, {}, function(err, entry) {
      if (err) return done.fail(err);

      // It won't be cached since the image doesn't exist
      expect(entry.html).toContain(absolutePathToImage);
      done();
    });
  });

  it("generates a blog post from an image with quotes in its filename", function(done) {
    var pathToImage = '/Hell"o\'W "orld.jpg';

    fs.copySync(__dirname + "/small.jpg", this.blogDirectory + pathToImage);

    build(this.blog, pathToImage, {}, function(err, entry) {
      if (err) return done.fail(err);

      // verify the image was cached
      expect(entry.html).toContain("/_image_cache/");

      // verify a thumbnail was generated from the image
      expect(entry.thumbnail.small).toEqual(
        jasmine.objectContaining({
          name: "small.jpg"
        })
      );

      done();
    });
  });

  it("handles images with accents and spaces in their filename", function(done) {
    var path = "/blog/Hello world.txt";
    var contents = "![Best Image Ever](óå g.jpg)";
    var pathToImage = "/blog/óå g.jpg";

    fs.outputFileSync(this.blogDirectory + path, contents);
    fs.copySync(__dirname + "/small.jpg", this.blogDirectory + pathToImage);

    build(this.blog, path, {}, function(err, entry) {
      if (err) return done.fail(err);

      // verify the image was cached
      expect(entry.html).toContain("/_image_cache/");

      // verify a thumbnail was generated from the image
      expect(entry.thumbnail.small).toEqual(
        jasmine.objectContaining({
          name: "small.jpg"
        })
      );

      done();
    });
  });

  it("will not use as image to become a thumbnail if it is too small", function(done) {
    var path = "/Hello world.txt";
    var contents = "![Best Image Ever](test.jpg)";
    var pathToImage = "/test.jpg";

    fs.outputFileSync(this.blogDirectory + path, contents);
    fs.copySync(__dirname + "/too-small.jpg", this.blogDirectory + pathToImage);

    build(this.blog, path, {}, function(err, entry) {
      if (err) return done.fail(err);

      // verify no thumbnail was generated from the image
      expect(entry.thumbnail).toEqual({});
      done();
    });
  });

  it("will not include caption text in summaries", function(done) {
    var path = "/Hello world.txt";
    var contents = "# Hello\n\n![Image caption](file.jpg)\n\nWorld";

    fs.outputFileSync(this.blogDirectory + path, contents);

    let blog = this.blog;
    blog.plugins.imageCaption.enabled = true;

    build(blog, path, {}, function(err, entry) {
      if (err) return done.fail(err);

      // verify a thumbnail was generated from the image
      expect(entry.summary).toEqual("World");

      done();
    });
  });

  it("will not generate a publish dateStamp for files without a date in their metadata or path", function(done) {
    var path = "/No-date-in-this-path.txt";
    var contents = "No date in this file";

    fs.outputFileSync(this.blogDirectory + path, contents);
    build(this.blog, path, {}, function(err, entry) {
      if (err) return done.fail(err);
      expect(entry.dateStamp).toEqual(undefined);
      done();
    });
  });

  it("will not cache image an image using the static query string", function(done) {
    var path = "/Hello world.txt";
    var contents = "";

    // we use an img tag instead of a markdown image because for
    // some reason the version of Pandoc running on Blot's CI server
    // creates <embed>'s instead of  for certain URLs
    fs.outputFileSync(this.blogDirectory + path, contents);

    build(this.blog, path, {}, function(err, entry) {
      if (err) return done.fail(err);

      // verify the image was not cached
      expect(entry.html).not.toContain("/_image_cache/");

      // verify a thumbnail was still generated from the image
      expect(entry.thumbnail.small).toEqual(
        jasmine.objectContaining({
          name: "small.jpg"
        })
      );

      done();
    });
  });
});
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import NumberInputText from './DialerComponents/NumberInputText';
import LogBox from './DialerComponents/LogBox';
import CallButton from './DialerComponents/CallButton';
import DTMFTone from './DialerComponents/DTMFTone';
import { connect } from 'react-redux';
import { FloatingActionButton, red500, green500 } from 'material-ui';

class Dialer extends Component {

  constructor(props) {
    super(props);
    this.state = {
      muted: false,
      log: 'Connecting...',
      onPhone: false,
      countryCode: '1',
      currentNumber: '',
      isValidNumber: false,
      receivingCall: false,
      callerId: ''
    };

    this.handleAcceptedCall = this.handleAcceptedCall.bind(this);
    this.handleDeclinedCall = this.handleDeclinedCall.bind(this);
    this.handleDialerInput = this.handleDialerInput.bind(this);
    this.handleToggleCall = this.handleToggleCall.bind(this);
    this.handleChangeNumber = this.handleChangeNumber.bind(this);
    this.handleDisconnectCall = this.handleDisconnectCall.bind(this);
    this.updateLog = this.updateLog.bind(this);
  }

  componentWillUpdate(nextProps, nextState) {
    if(nextProps.incomingCallConnection != null && nextProps.incomingCallConnection._status == 'pending') {
      nextState.receivingCall = true;
      nextState.callerId = nextProps.incomingCallConnection.parameters.From;
    }
  }

  componentDidMount() {
    if (this.props.incomingCallConnection != null) {
      this.setState({
        receivingCall: true,
        callerId: this.props.incomingCallConnection.parameters.From
      });
    }

    // need to add this functionality to the redux store!
    Twilio.Device.disconnect(() => {
      this.handleDisconnectCall();
    });
  }

  updateLog(text) {
    this.setState({ log: text });
  }

  // Handle number input
  handleChangeNumber(e) {
    this.setState({
      currentNumber: e.target.value,
      isValidNumber: /^([0-9]|#|\*)+$/.test(e.target.value.replace(/[-()\s]/g, ''))
    });
  }

  // Handle Dialer Input
  handleDialerInput(n) {
    const dial = `${this.state.currentNumber + n}`;
    this.setState({
      currentNumber: dial,
      isValidNumber: /^([0-9]|#|\*)+$/.test(dial.replace(/[-()\s]/g, ''))
    });
  }

  // Handle muting
  handleToggleMute() {
    const muted = !this.state.muted;

    this.setState({ muted });
    Twilio.Device.activeConnection().mute(muted);
  }

  // Make an outbound call with the current number,
  // or hang up the current call
  handleToggleCall() {
    if (!this.state.onPhone) {
      this.setState({
        muted: false,
        onPhone: true
      });
      // make outbound call with current number
      const n = `+1${this.state.currentNumber.replace(/\D/g, '')}`;
      // console.log(`Attempting to connect to: ${n}`);
      Twilio.Device.connect({ phoneNumber: n });
      this.setState({ log: `Calling ${n}` });
    } else {

      // hang up call in progress.
      Twilio.Device.disconnectAll();

      // Update state to make call button green again.
      this.setState({
        onPhone: false,
        log: 'Ended Call Successfully'
      });
    }
  }

  handleAcceptedCall() {
    this.props.incomingCallConnection.accept();
    this.setState({
      receivingCall: false,
      callerId: '',
      onPhone: true,
      currentNumber: this.props.incomingCallConnection.parameters.From
    });
  }

  handleDeclinedCall() {
    this.props.incomingCallConnection.ignore();
    this.setState({
      receivingCall: false,
      callerId: ''
    });
  }

  handleDisconnectCall() {
    this.setState({
      onPhone: false,
      log: 'Ended Call Successfully'
    });
  }

  render() {
    if (this.state.receivingCall == true) {
      return (

Incoming call from {this.state.callerId}

          <FloatingActionButton
            backgroundColor={'green500'}
            onClick={this.handleAcceptedCall}>Accept</FloatingActionButton>
          <FloatingActionButton
            backgroundColor={'red500'}
            onClick={this.handleDeclinedCall}>Decline</FloatingActionButton>

      );
    }
    else {
      return (

            <NumberInputText
              currentNumber={this.state.currentNumber}
              handleOnChange={this.handleChangeNumber} />

          <DTMFTone
            handleOnChange={this.handleDialerInput} />

          <CallButton
            handleOnClick={this.handleToggleCall}
            disabled={!this.state.isValidNumber}
            onPhone={this.state.onPhone} />

          <LogBox text={this.state.log} />

      );
    }
  }
}

function mapStateToProps(state) {
  return {
    incomingCallConnection: state.incomingCallConnection.connection
  }
}

export default connect(mapStateToProps)(Dialer);
<commit_msg>accpepting incoming call with enable the call button<commit_after>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import NumberInputText from './DialerComponents/NumberInputText';
import LogBox from './DialerComponents/LogBox';
import CallButton from './DialerComponents/CallButton';
import DTMFTone from './DialerComponents/DTMFTone';
import { connect } from 'react-redux';
import { FloatingActionButton, red500, green500 } from 'material-ui';

class Dialer extends Component {

  constructor(props) {
    super(props);
    this.state = {
      muted: false,
      log: 'Connecting...',
      onPhone: false,
      countryCode: '1',
      currentNumber: '',
      isValidNumber: false,
      receivingCall: false,
      callerId: ''
    };

    this.handleAcceptedCall = this.handleAcceptedCall.bind(this);
    this.handleDeclinedCall = this.handleDeclinedCall.bind(this);
    this.handleDialerInput = this.handleDialerInput.bind(this);
    this.handleToggleCall = this.handleToggleCall.bind(this);
    this.handleChangeNumber = this.handleChangeNumber.bind(this);
    this.handleDisconnectCall = this.handleDisconnectCall.bind(this);
    this.updateLog = this.updateLog.bind(this);
  }

  componentWillUpdate(nextProps, nextState) {
    if(nextProps.incomingCallConnection != null && nextProps.incomingCallConnection._status == 'pending') {
      nextState.receivingCall = true;
      nextState.callerId = nextProps.incomingCallConnection.parameters.From;
    }
  }

  componentDidMount() {
    if (this.props.incomingCallConnection != null) {
      this.setState({
        receivingCall: true,
        callerId: this.props.incomingCallConnection.parameters.From
      });
    }

    // need to add this functionality to the redux store!
    Twilio.Device.disconnect(() => {
      this.handleDisconnectCall();
    });
  }

  updateLog(text) {
    this.setState({ log: text });
  }

  // Handle number input
  handleChangeNumber(e) {
    this.setState({
      currentNumber: e.target.value,
      isValidNumber: /^([0-9]|#|\*)+$/.test(e.target.value.replace(/[-()\s]/g, ''))
    });
  }

  // Handle Dialer Input
  handleDialerInput(n) {
    const dial = `${this.state.currentNumber + n}`;
    this.setState({
      currentNumber: dial,
      isValidNumber: /^([0-9]|#|\*)+$/.test(dial.replace(/[-()\s]/g, ''))
    });
  }

  // Handle muting
  handleToggleMute() {
    const muted = !this.state.muted;

    this.setState({ muted });
    Twilio.Device.activeConnection().mute(muted);
  }

  // Make an outbound call with the current number,
  // or hang up the current call
  handleToggleCall() {
    if (!this.state.onPhone) {
      this.setState({
        muted: false,
        onPhone: true
      });
      // make outbound call with current number
      const n = `+1${this.state.currentNumber.replace(/\D/g, '')}`;
      // console.log(`Attempting to connect to: ${n}`);
      Twilio.Device.connect({ phoneNumber: n });
      this.setState({ log: `Calling ${n}` });
    } else {

      // hang up call in progress.
      Twilio.Device.disconnectAll();

      // Update state to make call button green again.
      this.setState({
        onPhone: false,
        log: 'Ended Call Successfully'
      });
    }
  }

  handleAcceptedCall() {
    this.props.incomingCallConnection.accept();
    this.setState({
      receivingCall: false,
      callerId: '',
      onPhone: true,
      currentNumber: this.props.incomingCallConnection.parameters.From,
      isValidNumber: true
    });
  }

  handleDeclinedCall() {
    this.props.incomingCallConnection.ignore();
    this.setState({
      receivingCall: false,
      callerId: ''
    });
  }

  handleDisconnectCall() {
    this.setState({
      onPhone: false,
      log: 'Ended Call Successfully'
    });
  }

  render() {
    if (this.state.receivingCall == true) {
      return (

Incoming call from {this.state.callerId}

          <FloatingActionButton
            backgroundColor={'green500'}
            onClick={this.handleAcceptedCall}>Accept</FloatingActionButton>
          <FloatingActionButton
            backgroundColor={'red500'}
            onClick={this.handleDeclinedCall}>Decline</FloatingActionButton>

      );
    }
    else {
      return (

            <NumberInputText
              currentNumber={this.state.currentNumber}
              handleOnChange={this.handleChangeNumber} />

          <DTMFTone
            handleOnChange={this.handleDialerInput} />

          <CallButton
            handleOnClick={this.handleToggleCall}
            disabled={!this.state.isValidNumber}
            onPhone={this.state.onPhone} />

          <LogBox text={this.state.log} />

      );
    }
  }
}

function mapStateToProps(state) {
  return {
    incomingCallConnection: state.incomingCallConnection.connection
  }
}

export default connect(mapStateToProps)(Dialer);
<|endoftext|>


<commit_before>/*
 * Navigation and search bar for the top of the app, to allow the user to search from anywhere.
 */
'use strict';

// React imports
const React = require('react-native');
const {
  Component,
  Dimensions,
  LayoutAnimation,
  Platform,
  StyleSheet,
  TouchableOpacity,
  TextInput,
  View,
} = React;

const Constants = require('../Constants');
const Ionicons = require('react-native-vector-icons/Ionicons');
const MaterialIcons = require('react-native-vector-icons/MaterialIcons');
const Preferences = require('../util/Preferences');
const StatusBar = require('../util/StatusBar');

const {height, width} = Dimensions.get('window');

// Declaring icons depending on the platform
var Icon;
var backIcon;
if (Platform.OS === 'ios') {
  Icon = Ionicons;
  backIcon = 'ios-arrow-back';
} else {
  Icon = require('react-native-vector-icons/MaterialIcons');
  backIcon = 'arrow-back';
}

class SearchBar extends Component {

  /*
   * Properties which the parent component should make available to this component.
   */
  static propTypes = {
    onSearch: React.PropTypes.func.isRequired,
    onBack: React.PropTypes.func.isRequired,
  };

  /*
   * Pass props.
   */
  constructor(props) {
    super(props);
    this.state = {
      showBackButton: false,
      refresh: false,
    };

    // Explicitly binding 'this' to certain methods
    this.getRefresh = this.getRefresh.bind(this);
  };

  /*
   * Configures the app to animate the next layout change, then updates the state.
   */
  setState(state) {
    LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
    super.setState(state);
  };

  /*
   * Returns the current state of the refresh variable, to allow it to be flipped to re-render the view.
   */
  getRefresh() {
    return this.state.refresh;
  };

  /*
   * Clears the search field and requests a back navigation.
   */
  _onBack() {
    this.refs.SearchInput.setNativeProps({text: ''});
    this.props.onBack();
  };

  /*
   * Prompts the app to search, so long as there is any text to search with.
   */
  _onSearch(text) {
    if (text && text.length > 0) {
      this.props.onSearch(text);
    }
  };

  /*
   * Renders a text input field for searching.
   */
  render() {
    // Get current language for translations
    let Translations = null;
    if (Preferences.getSelectedLanguage() === 'en') {
      Translations = require('../util/Translations.en.js');
    } else {
      Translations = require('../util/Translations.fr.js');
    }

    // Setting position of search bar and back button dependent on if back button is showing.
    let searchBarLeft = (this.state.showBackButton)
        ? 50
        : 10;
    let searchBarWidth = (this.state.showBackButton)
        ? width - 60
        : width - 20;
    let backButtonLeft = (this.state.showBackButton)
        ? 0
        : -60;

    return (
      <View style={_styles.container}>
        <TouchableOpacity onPress={this._onBack.bind(this)} style={{height: 40, alignItems: 'center', left: backButtonLeft}}>
          <Icon name={backIcon} size={24} color={'white'} style={{marginLeft: 20, marginRight: 20, marginTop: 8}} />
        </TouchableOpacity>
        <View style={[_styles.innerContainer, {position: 'absolute', width: searchBarWidth, left: searchBarLeft, top: 0}]}>
          <Ionicons
              onPress={() => this.refs.SearchInput.focus()}
              name={'ios-search'}
              size={24}
              color={'white'}
              style={{marginLeft: 10, marginRight: 10}} />
          <TextInput
              ref='SearchInput'
              style={{flex: 1, height: 40, color: Constants.Colors.polarGrey}}
              onChangeText={this._onSearch.bind(this)}
              autoCorrect={false}
              placeholder={Translations['search_placeholder']}
              placeholderTextColor={Constants.Colors.lightGrey} />
        </View>
      </View>
    )
  };
};

// Private styles for component
const _styles = StyleSheet.create({
  container: {
    flexDirection: 'row',
    alignItems: 'center',
    height: 60,
    marginTop: StatusBar.getStatusBarPadding(),
  },
  innerContainer: {
    alignItems: 'center',
    flexDirection: 'row',
    borderRadius: 10,
    backgroundColor: 'rgba(0, 0, 0, 0.2)',
    margin: 10,
    marginLeft: 0,
  }
});

// Expose component to app
module.exports = SearchBar;
<commit_msg>Delay navbar refresh animation to prevent effects on other components<commit_after>/*
 * Navigation and search bar for the top of the app, to allow the user to search from anywhere.
 */
'use strict';

// React imports
const React = require('react-native');
const {
  Component,
  Dimensions,
  LayoutAnimation,
  Platform,
  StyleSheet,
  TouchableOpacity,
  TextInput,
  View,
} = React;

import TimerMixin from 'react-timer-mixin';
const Constants = require('../Constants');
const Ionicons = require('react-native-vector-icons/Ionicons');
const MaterialIcons = require('react-native-vector-icons/MaterialIcons');
const Preferences = require('../util/Preferences');
const StatusBar = require('../util/StatusBar');

const {height, width} = Dimensions.get('window');

// Declaring icons depending on the platform
var Icon;
var backIcon;
if (Platform.OS === 'ios') {
  Icon = Ionicons;
  backIcon = 'ios-arrow-back';
} else {
  Icon = require('react-native-vector-icons/MaterialIcons');
  backIcon = 'arrow-back';
}

class SearchBar extends Component {

  /*
   * Properties which the parent component should make available to this component.
   */
  static propTypes = {
    onSearch: React.PropTypes.func.isRequired,
    onBack: React.PropTypes.func.isRequired,
  };

  /*
   * Pass props.
   */
  constructor(props) {
    super(props);
    this.state = {
      showBackButton: false,
      refresh: false,
    };

    // Explicitly binding 'this' to certain methods
    this.getRefresh = this.getRefresh.bind(this);

  };

  /*
   * Configures the app to animate the next layout change, then updates the state.
   */
  setState(state) {
    setTimeout(() => {
      LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
      super.setState(state);
    }, 50);
  };

  /*
   * Returns the current state of the refresh variable, to allow it to be flipped to re-render the view.
   */
  getRefresh() {
    return this.state.refresh;
  };

  /*
   * Clears the search field and requests a back navigation.
   */
  _onBack() {
    this.refs.SearchInput.setNativeProps({text: ''});
    this.props.onBack();
  };

  /*
   * Prompts the app to search, so long as there is any text to search with.
   */
  _onSearch(text) {
    if (text && text.length > 0) {
      this.props.onSearch(text);
    }
  };

  /*
   * Renders a text input field for searching.
   */
  render() {
    // Get current language for translations
    let Translations = null;
    if (Preferences.getSelectedLanguage() === 'en') {
      Translations = require('../util/Translations.en.js');
    } else {
      Translations = require('../util/Translations.fr.js');
    }

    // Setting position of search bar and back button dependent on if back button is showing.
    let searchBarLeft = (this.state.showBackButton)
        ? 50
        : 10;
    let searchBarWidth = (this.state.showBackButton)
        ? width - 60
        : width - 20;
    let backButtonLeft = (this.state.showBackButton)
        ? 0
        : -60;

    return (
      <View style={_styles.container}>
        <TouchableOpacity onPress={this._onBack.bind(this)} style={{height: 40, alignItems: 'center', left: backButtonLeft}}>
          <Icon name={backIcon} size={24} color={'white'} style={{marginLeft: 20, marginRight: 20, marginTop: 8}} />
        </TouchableOpacity>
        <View style={[_styles.innerContainer, {position: 'absolute', width: searchBarWidth, left: searchBarLeft, top: 0}]}>
          <Ionicons
              onPress={() => this.refs.SearchInput.focus()}
              name={'ios-search'}
              size={24}
              color={'white'}
              style={{marginLeft: 10, marginRight: 10}} />
          <TextInput
              ref='SearchInput'
              style={{flex: 1, height: 40, color: Constants.Colors.polarGrey}}
              onChangeText={this._onSearch.bind(this)}
              autoCorrect={false}
              placeholder={Translations['search_placeholder']}
              placeholderTextColor={Constants.Colors.lightGrey} />
        </View>
      </View>
    )
  };
};

// Private styles for component
const _styles = StyleSheet.create({
  container: {
    flexDirection: 'row',
    alignItems: 'center',
    height: 60,
    marginTop: StatusBar.getStatusBarPadding(),
  },
  innerContainer: {
    alignItems: 'center',
    flexDirection: 'row',
    borderRadius: 10,
    backgroundColor: 'rgba(0, 0, 0, 0.2)',
    margin: 10,
    marginLeft: 0,
  }
});

// Expose component to app
module.exports = SearchBar;
<|endoftext|>


<commit_before>hqDefine('toggle_ui/js/edit-flag', [
    'jquery',
    'knockout',
    'underscore',
    'hqwebapp/js/initial_page_data',
    'hqwebapp/js/main',
    'hqwebapp/js/knockout_bindings.ko',     // save button
], function (
    $,
    ko,
    _,
    initialPageData,
    hqMain
) {
    var PAD_CHAR = ' ';
    function ToggleView() {
        var self = this;
        self.items = ko.observableArray();
        self.randomness = ko.observable();

        self.init = function (config) {
            self.padded_ns = {};
            var max_ns_len = Math.max.apply(Math, _.map(config.namespaces, function (ns) { return ns.length; }));
            _(config.namespaces).each(function (namespace) {
                var diff = max_ns_len - namespace.length,
                    pad = new Array(diff + 1).join(PAD_CHAR);
                self.padded_ns[namespace] = namespace + pad;
            });
            self.init_items(config);
            self.latest_use = ko.observable(config.last_used._latest || '');
            self.randomness(config.randomness);
        };

        self.init_items = function (config) {
            var items = config.items,
                last_used = config.last_used || {};
            self.items.removeAll();
            _(items).each(function (item) {
                var fields = item.split(':'),
                    namespace = fields.length > 1 ? fields[0] : 'user',
                    value = fields.length > 1 ? fields[1] : fields[0];
                self.items.push({
                    namespace: ko.observable(self.padded_ns[namespace]),
                    value: ko.observable(value),
                    last_used: ko.observable(last_used[value]),
                });
            });
        };

        self.addItem = function (namespace) {
            self.items.push({
                namespace: ko.observable(self.padded_ns[namespace]),
                value: ko.observable(),
                last_used: ko.observable(),
            });
            self.change();
        };

        self.removeItem = function (item) {
            self.items.remove(item);
            self.change();
        };

        self.change = function () {
            self.saveButton.fire('change');
        };

        self.saveButton = hqMain.initSaveButton({
            unsavedMessage: "You have unsaved changes",
            save: function () {
                var items = _.map(self.items(), function (item) {
                    var ns_raw = item.namespace().replace(new RegExp(PAD_CHAR, 'g'), ''),
                        namespace = ns_raw === 'user' ? null : ns_raw,
                        value = namespace === null ? item.value() : namespace + ':' + item.value();
                    return value;
                });
                self.saveButton.ajax({
                    type: 'post',
                    url: initialPageData.reverse('edit_toggle') + location.search,
                    data: {
                        item_list: JSON.stringify(items),
                        randomness: self.randomness(),
                    },
                    dataType: 'json',
                    success: function (data) {
                        self.init_items(data);
                    },
                });
            },
        });

        var projectInfoUrl = 'domain';
        self.getNamespaceHtml = function(namespace, value) {
            if (namespace === 'domain') {
                return projectInfoUrl.replace('___', value);
            } else {
                return namespace;
            }
        };

    }

    $(function(){
        var $home = $('#toggle_editing_ko');
        var view = new ToggleView();
        view.init({
            items: initialPageData.get('items'),
            namespaces: initialPageData.get('namespaces'),
            last_used: initialPageData.get('last_used'),
            is_random_editable: initialPageData.get('is_random_editable'),
            randomness: initialPageData.get('randomness'),
        });
        $home.koApplyBindings(view);
        $home.on('change', 'input', view.change);
    });
});
<commit_msg>Feature flag<commit_after>hqDefine('toggle_ui/js/edit-flag', [
    'jquery',
    'knockout',
    'underscore',
    'hqwebapp/js/initial_page_data',
    'hqwebapp/js/main',
    'hqwebapp/js/knockout_bindings.ko',     // save button
], function (
    $,
    ko,
    _,
    initialPageData,
    hqMain
) {
    var PAD_CHAR = ' ';
    function toggleViewModel() {
        var self = {};
        self.items = ko.observableArray();
        self.randomness = ko.observable();

        self.init = function (config) {
            self.padded_ns = {};
            var max_ns_len = Math.max.apply(Math, _.map(config.namespaces, function (ns) { return ns.length; }));
            _(config.namespaces).each(function (namespace) {
                var diff = max_ns_len - namespace.length,
                    pad = new Array(diff + 1).join(PAD_CHAR);
                self.padded_ns[namespace] = namespace + pad;
            });
            self.init_items(config);
            self.latest_use = ko.observable(config.last_used._latest || '');
            self.randomness(config.randomness);
        };

        self.init_items = function (config) {
            var items = config.items,
                last_used = config.last_used || {};
            self.items.removeAll();
            _(items).each(function (item) {
                var fields = item.split(':'),
                    namespace = fields.length > 1 ? fields[0] : 'user',
                    value = fields.length > 1 ? fields[1] : fields[0];
                self.items.push({
                    namespace: ko.observable(self.padded_ns[namespace]),
                    value: ko.observable(value),
                    last_used: ko.observable(last_used[value]),
                });
            });
        };

        self.addItem = function (namespace) {
            self.items.push({
                namespace: ko.observable(self.padded_ns[namespace]),
                value: ko.observable(),
                last_used: ko.observable(),
            });
            self.change();
        };

        self.removeItem = function (item) {
            self.items.remove(item);
            self.change();
        };

        self.change = function () {
            self.saveButton.fire('change');
        };

        self.saveButton = hqMain.initSaveButton({
            unsavedMessage: "You have unsaved changes",
            save: function () {
                var items = _.map(self.items(), function (item) {
                    var ns_raw = item.namespace().replace(new RegExp(PAD_CHAR, 'g'), ''),
                        namespace = ns_raw === 'user' ? null : ns_raw,
                        value = namespace === null ? item.value() : namespace + ':' + item.value();
                    return value;
                });
                self.saveButton.ajax({
                    type: 'post',
                    url: initialPageData.reverse('edit_toggle') + location.search,
                    data: {
                        item_list: JSON.stringify(items),
                        randomness: self.randomness(),
                    },
                    dataType: 'json',
                    success: function (data) {
                        self.init_items(data);
                    },
                });
            },
        });

        var projectInfoUrl = 'domain';
        self.getNamespaceHtml = function(namespace, value) {
            if (namespace === 'domain') {
                return projectInfoUrl.replace('___', value);
            } else {
                return namespace;
            }
        };

        return self;
    }

    $(function(){
        var $home = $('#toggle_editing_ko');
        var view = toggleViewModel();
        view.init({
            items: initialPageData.get('items'),
            namespaces: initialPageData.get('namespaces'),
            last_used: initialPageData.get('last_used'),
            is_random_editable: initialPageData.get('is_random_editable'),
            randomness: initialPageData.get('randomness'),
        });
        $home.koApplyBindings(view);
        $home.on('change', 'input', view.change);
    });
});
<|endoftext|>