<commit_before>goog.provide('ol.interaction.PinchRotate');

goog.require('goog.asserts');
goog.require('goog.functions');
goog.require('goog.style');
goog.require('ol.Coordinate');
goog.require('ol.ViewHint');
goog.require('ol.interaction.Interaction');
goog.require('ol.interaction.Pointer');

/**
 * @classdesc
 * Allows the user to rotate the map by twisting with two fingers
 * on a touch screen.
 *
 * @constructor
 * @extends {ol.interaction.Pointer}
 * @param {olx.interaction.PinchRotateOptions=} opt_options Options.
 * @api stable
 */
ol.interaction.PinchRotate = function(opt_options) {

  goog.base(this, {
    handleDownEvent: ol.interaction.PinchRotate.handleDownEvent_,
    handleDragEvent: ol.interaction.PinchRotate.handleDragEvent_,
    handleUpEvent: ol.interaction.PinchRotate.handleUpEvent_
  });

  var options = goog.isDef(opt_options) ? opt_options : {};

  /**
   * @private
   * @type {ol.Coordinate}
   */
  this.anchor_ = null;

  /**
   * @private
   * @type {number|undefined}
   */
  this.lastAngle_ = undefined;

  /**
   * @private
   * @type {boolean}
   */
  this.rotating_ = false;

  /**
   * @private
   * @type {number}
   */
  this.rotationDelta_ = 0.0;

  /**
   * @private
   * @type {number}
   */
  this.threshold_ = goog.isDef(options.threshold) ? options.threshold : 0.3;

  /**
   * @private
   * @type {number}
   */
  this.duration_ = goog.isDef(options.duration) ? options.duration : 250;

};
goog.inherits(ol.interaction.PinchRotate, ol.interaction.Pointer);

/**
 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
 * @this {ol.interaction.PinchRotate}
 * @private
 */
ol.interaction.PinchRotate.handleDragEvent_ = function(mapBrowserEvent) {
  goog.asserts.assert(this.targetPointers.length >= 2,
      'length of this.targetPointers should be greater than or equal to 2');
  var rotationDelta = 0.0;

  var touch0 = this.targetPointers[0];
  var touch1 = this.targetPointers[1];

  // angle between touches
  var angle = Math.atan2(
      touch1.clientY - touch0.clientY,
      touch1.clientX - touch0.clientX);

  if (goog.isDef(this.lastAngle_)) {
    var delta = angle - this.lastAngle_;
    this.rotationDelta_ += delta;
    if (!this.rotating_ &&
        Math.abs(this.rotationDelta_) > this.threshold_) {
      this.rotating_ = true;
    }
    rotationDelta = delta;
  }
  this.lastAngle_ = angle;

  var map = mapBrowserEvent.map;

  // rotate anchor point.
  // FIXME: should be the intersection point between the lines:
  //     touch0,touch1 and previousTouch0,previousTouch1
  var viewportPosition = goog.style.getClientPosition(map.getViewport());
  var centroid =
      ol.interaction.Pointer.centroid(this.targetPointers);
  centroid[0] -= viewportPosition.x;
  centroid[1] -= viewportPosition.y;
  this.anchor_ = map.getCoordinateFromPixel(centroid);

  // rotate
  if (this.rotating_) {
    var view = map.getView();
    var rotation = view.getRotation();
    map.render();
    ol.interaction.Interaction.rotateWithoutConstraints(map, view,
        rotation + rotationDelta, this.anchor_);
  }
};

/**
 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
 * @return {boolean} Stop drag sequence?
 * @this {ol.interaction.PinchRotate}
 * @private
 */
ol.interaction.PinchRotate.handleUpEvent_ = function(mapBrowserEvent) {
  if (this.targetPointers.length < 2) {
    var map = mapBrowserEvent.map;
    var view = map.getView();
    view.setHint(ol.ViewHint.INTERACTING, -1);
    if (this.rotating_) {
      var rotation = view.getRotation();
      ol.interaction.Interaction.rotate(
          map, view, rotation, this.anchor_, this.duration_);
    }
    return false;
  } else {
    return true;
  }
};

/**
 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
 * @return {boolean} Start drag sequence?
 * @this {ol.interaction.PinchRotate}
 * @private
 */
ol.interaction.PinchRotate.handleDownEvent_ = function(mapBrowserEvent) {
  if (this.targetPointers.length >= 2) {
    var map = mapBrowserEvent.map;
    this.anchor_ = null;
    this.lastAngle_ = undefined;
    this.rotating_ = false;
    this.rotationDelta_ = 0.0;
    if (!this.handlingDownUpSequence) {
      map.getView().setHint(ol.ViewHint.INTERACTING, 1);
    }
    map.render();
    return true;
  } else {
    return false;
  }
};

/**
 * @inheritDoc
 */
ol.interaction.PinchRotate.prototype.shouldStopEvent = goog.functions.FALSE;
<commit_msg>Remove goog.isDef from pinchrotateinteraction<commit_after>goog.provide('ol.interaction.PinchRotate');

goog.require('goog.asserts');
goog.require('goog.functions');
goog.require('goog.style');
goog.require('ol');
goog.require('ol.Coordinate');
goog.require('ol.ViewHint');
goog.require('ol.interaction.Interaction');
goog.require('ol.interaction.Pointer');

/**
 * @classdesc
 * Allows the user to rotate the map by twisting with two fingers
 * on a touch screen.
 *
 * @constructor
 * @extends {ol.interaction.Pointer}
 * @param {olx.interaction.PinchRotateOptions=} opt_options Options.
 * @api stable
 */
ol.interaction.PinchRotate = function(opt_options) {

  goog.base(this, {
    handleDownEvent: ol.interaction.PinchRotate.handleDownEvent_,
    handleDragEvent: ol.interaction.PinchRotate.handleDragEvent_,
    handleUpEvent: ol.interaction.PinchRotate.handleUpEvent_
  });

  var options = ol.isDef(opt_options) ? opt_options : {};

  /**
   * @private
   * @type {ol.Coordinate}
   */
  this.anchor_ = null;

  /**
   * @private
   * @type {number|undefined}
   */
  this.lastAngle_ = undefined;

  /**
   * @private
   * @type {boolean}
   */
  this.rotating_ = false;

  /**
   * @private
   * @type {number}
   */
  this.rotationDelta_ = 0.0;

  /**
   * @private
   * @type {number}
   */
  this.threshold_ = ol.isDef(options.threshold) ?
      /** @type {number} */ (options.threshold) : 0.3;

  /**
   * @private
   * @type {number}
   */
  this.duration_ = ol.isDef(options.duration) ?
      /** @type {number} */ (options.duration) : 250;

};
goog.inherits(ol.interaction.PinchRotate, ol.interaction.Pointer);

/**
 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
 * @this {ol.interaction.PinchRotate}
 * @private
 */
ol.interaction.PinchRotate.handleDragEvent_ = function(mapBrowserEvent) {
  goog.asserts.assert(this.targetPointers.length >= 2,
      'length of this.targetPointers should be greater than or equal to 2');
  var rotationDelta = 0.0;

  var touch0 = this.targetPointers[0];
  var touch1 = this.targetPointers[1];

  // angle between touches
  var angle = Math.atan2(
      touch1.clientY - touch0.clientY,
      touch1.clientX - touch0.clientX);

  if (ol.isDef(this.lastAngle_)) {
    var delta = angle - this.lastAngle_;
    this.rotationDelta_ += delta;
    if (!this.rotating_ &&
        Math.abs(this.rotationDelta_) > this.threshold_) {
      this.rotating_ = true;
    }
    rotationDelta = delta;
  }
  this.lastAngle_ = angle;

  var map = mapBrowserEvent.map;

  // rotate anchor point.
  // FIXME: should be the intersection point between the lines:
  //     touch0,touch1 and previousTouch0,previousTouch1
  var viewportPosition = goog.style.getClientPosition(map.getViewport());
  var centroid =
      ol.interaction.Pointer.centroid(this.targetPointers);
  centroid[0] -= viewportPosition.x;
  centroid[1] -= viewportPosition.y;
  this.anchor_ = map.getCoordinateFromPixel(centroid);

  // rotate
  if (this.rotating_) {
    var view = map.getView();
    var rotation = view.getRotation();
    map.render();
    ol.interaction.Interaction.rotateWithoutConstraints(map, view,
        rotation + rotationDelta, this.anchor_);
  }
};

/**
 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
 * @return {boolean} Stop drag sequence?
 * @this {ol.interaction.PinchRotate}
 * @private
 */
ol.interaction.PinchRotate.handleUpEvent_ = function(mapBrowserEvent) {
  if (this.targetPointers.length < 2) {
    var map = mapBrowserEvent.map;
    var view = map.getView();
    view.setHint(ol.ViewHint.INTERACTING, -1);
    if (this.rotating_) {
      var rotation = view.getRotation();
      ol.interaction.Interaction.rotate(
          map, view, rotation, this.anchor_, this.duration_);
    }
    return false;
  } else {
    return true;
  }
};

/**
 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
 * @return {boolean} Start drag sequence?
 * @this {ol.interaction.PinchRotate}
 * @private
 */
ol.interaction.PinchRotate.handleDownEvent_ = function(mapBrowserEvent) {
  if (this.targetPointers.length >= 2) {
    var map = mapBrowserEvent.map;
    this.anchor_ = null;
    this.lastAngle_ = undefined;
    this.rotating_ = false;
    this.rotationDelta_ = 0.0;
    if (!this.handlingDownUpSequence) {
      map.getView().setHint(ol.ViewHint.INTERACTING, 1);
    }
    map.render();
    return true;
  } else {
    return false;
  }
};

/**
 * @inheritDoc
 */
ol.interaction.PinchRotate.prototype.shouldStopEvent = goog.functions.FALSE;
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import ApplicationRSVPToggle from "./ApplicationRSVPToggle";

class ApplicationForm extends Component {
    render () {
        // let decisionMap = {
        //     4: 'EXPIRED',
        //     3: 'ACCEPT',
        //     2: 'WAITLIST',
        //     1: 'REJECT',
        //     0: 'UNDECIDED'
        // };
        const { applicationForm }  = this.props.application;
        const isLoading = this.props.application.loading;

        let transitMessage;
        switch(applicationForm.school.transit_method) {
            case "bus":
                transitMessage =

We'll be sending a bus to {applicationForm.school.name}!

Join the Facebook event <a href={`https://www.facebook.com/events/${applicationForm.school.facebook_event_id}`}>here to stay up to date!

;
                break;
            case "car":
                transitMessage =

Sadly we won't be able to send a bus to {applicationForm.school.name}.

However, if you're willing to get here by your own means, we'd love to have you!.

Note that we will not be providing any form of travel reimbursements.

;
                break;
            case "walk":
                transitMessage =
Well, you have it easy! BoilerMake will be happening in the Black & Gold Gyms of the CoRec on campus.
;
                break;
        }

        let rsvpYes =

neat! a few last things.

Providing us with a phone number (optional) will allow us to send you important event updates!
                    We will be providing everyone with lanyard nametags, you can pick up to 3 skills to be displayed on them.
                    Lastly, if you have any special dietary requests, please email us!

                        Phone #
                        <ApplicationTextField field="phone"/>

                        Pick up to 3 Skills
                        <ApplicationSelectField field="skills" multi searchable options={skillOptions}/>

                        idk what to put here
                        <ApplicationTextField field="phone"/>

                        Dietary Restrictions
                        <ApplicationSelectField field="diet" multi searchable options={dietOptions}/>

                <button disabled={isLoading} onClick={()=>{this.props.saveApplication(false, true)}} className="submit">Save RSVP</button>

;

        let rsvpNo =
aw sad :( please come back and apply next year though!
;

        let decisionForm;
        switch(applicationForm.decision) {
            case 3://ACCEPT
                decisionForm = (

You're in! yay.

We'd love to have you come to BoilerMake V this fall.

Getting to BoilerMake

                    {transitMessage}
                    Can you come? you must RSVP by {applicationForm.rsvp_deadline} or else we will offer your spot to someone else.
                    <ApplicationRSVPToggle/>
                    {
                        applicationForm.rsvp !== null
                        ? applicationForm.rsvp === 1
                            ? rsvpYes
                            : rsvpNo
                        : null//don't show rest of form if they haven't clicked yes or no yet
                    }

);
                break;
            case 2://WAITLIST
                decisionForm = (

You're waitlisted :(

[message]

);
                break;
            case 4://EXPIRED
                decisionForm = (

Your offer has expired expired :(

[message]

);
                break;
        }
        return (

                {decisionForm}

        );
    }
}

//now the redux integration layer
import {
    saveApplication,
    toggleApplicationFieldValue
} from '../../actions/application';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux'
import ApplicationTextField from "./ApplicationTextField";
import {dietOptions, skillOptions} from "./ApplicationConsts";
import ApplicationSelectField from "./ApplicationSelectField";
function mapStateToProps (state) {
    return {
        user: state.user,
        application: state.application,
    };
}

const mapDispatchToProps = (dispatch) => {
    return bindActionCreators({
        saveApplication,
        toggleApplicationFieldValue
    }, dispatch)
};

export default connect(mapStateToProps, mapDispatchToProps)(ApplicationForm);
<commit_msg>fix styles<commit_after>import React, { Component } from 'react';
import ApplicationTextField from "./ApplicationTextField";
import ApplicationSelectField from "./ApplicationSelectField";
import ApplicationRSVPToggle from "./ApplicationRSVPToggle";
import {dietOptions, skillOptions} from "./ApplicationConsts";

class ApplicationForm extends Component {
    render () {
        // let decisionMap = {
        //     4: 'EXPIRED',
        //     3: 'ACCEPT',
        //     2: 'WAITLIST',
        //     1: 'REJECT',
        //     0: 'UNDECIDED'
        // };
        const { applicationForm }  = this.props.application;
        const isLoading = this.props.application.loading;

        let transitMessage;
        switch(applicationForm.school.transit_method) {
            case "bus":
                transitMessage =

We'll be sending a bus to {applicationForm.school.name}!

Join the Facebook event <a href={`https://www.facebook.com/events/${applicationForm.school.facebook_event_id}`}>here to stay up to date!

;
                break;
            case "car":
                transitMessage =

Sadly we won't be able to send a bus to {applicationForm.school.name}.

However, if you're willing to get here by your own means, we'd love to have you!.

Note that we will not be providing any form of travel reimbursements.

;
                break;
            default:
            case "walk":
                transitMessage =
Well, you have it easy! BoilerMake will be happening in the Black & Gold Gyms of the CoRec on campus.
;
                break;
        }

        let rsvpYes =

neat! a few last things.

Providing us with a phone number (optional) will allow us to send you important event updates!
                    We will be providing everyone with lanyard nametags, you can pick up to 3 skills to be displayed on them.
                    Lastly, if you have any special dietary requests, please email us!

                        Phone #
                        <ApplicationTextField field="phone"/>

                        Pick up to 3 Skills
                        <ApplicationSelectField field="skills" multi searchable options={skillOptions}/>

                        idk what to put here
                        <ApplicationTextField field="phone"/>

                        Dietary Restrictions
                        <ApplicationSelectField field="diet" multi searchable options={dietOptions}/>

                <button disabled={isLoading} onClick={()=>{this.props.saveApplication(false, true)}} className="submit">Save RSVP</button>

;

        let rsvpNo =
aw sad :( please come back and apply next year though!
;

        let decisionForm;
        switch(applicationForm.decision) {
            case 3://ACCEPT
                decisionForm = (

You're in! yay.

We'd love to have you come to BoilerMake V this fall.

Getting to BoilerMake

                    {transitMessage}
                    Can you come? you must RSVP by {applicationForm.rsvp_deadline} or else we will offer your spot to someone else.
                    <ApplicationRSVPToggle/>
                    {
                        applicationForm.rsvp !== null
                        ? applicationForm.rsvp === 1
                            ? rsvpYes
                            : rsvpNo
                        : null//don't show rest of form if they haven't clicked yes or no yet
                    }

);
                break;
            case 2://WAITLIST
                decisionForm = (

You're waitlisted :(

[message]

);
                break;
            case 4://EXPIRED
                decisionForm = (

Your offer has expired expired :(

[message]

);
                break;
            default:
                decisionForm =
error

        }
        return (

                {decisionForm}

        );
    }
}

//now the redux integration layer
import {
    saveApplication,
    toggleApplicationFieldValue
} from '../../actions/application';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux'
function mapStateToProps (state) {
    return {
        user: state.user,
        application: state.application,
    };
}

const mapDispatchToProps = (dispatch) => {
    return bindActionCreators({
        saveApplication,
        toggleApplicationFieldValue
    }, dispatch)
};

export default connect(mapStateToProps, mapDispatchToProps)(ApplicationForm);
<|endoftext|>


<commit_before>import Base from "@patternslib/patternslib/src/core/base";
import dom from "@patternslib/patternslib/src/core/dom";
import utils from "../../core/utils";

export default Base.extend({
    name: "markspeciallinks",
    trigger: ".pat-markspeciallinks",
    parser: "mockup",

    defaults: {
        external_links_open_new_window: false,
        mark_special_links: true,
    },

    protocol_icon_map: {
        // For a list of supported default protocol hander, see:
        // https://developer.mozilla.org/en-US/docs/Web/API/Navigator/registerProtocolHandler#permitted_schemes
        https: "link-45deg",
        http: "link-45deg",
        ftp: "cloud-download", // deprecated
        callto: "telephone", // non-standard for skype
        bitcoin: "credit-card", // no bitcoin icon yet
        geo: "geo-alt",
        im: "chat",
        irc: "chat",
        ircs: "chat",
        magnet: "link-45deg",
        mailto: "envelope",
        mms: "chat",
        news: "newspaper",
        nntp: "newspaper",
        openpgp4fpr: "key",
        sip: "telephone",
        sms: "chat",
        smsto: "chat",
        ssh: "lock",
        tel: "telephone",
        urn: "link-45deg",
        webcal: "calendar",
        wtai: "telephone",
        xmpp: "chat",
    },

    async init() {
        // first make external links open in a new window, afterwards do the
        // normal plone link wrapping in only the content area

        let open_new_window = false;
        if (typeof this.options.external_links_open_new_window === "string") {
            open_new_window =
                this.options.external_links_open_new_window.toLowerCase() === "true";
        } else if (typeof this.options.external_links_open_new_window === "boolean") {
            open_new_window = this.options.external_links_open_new_window;
        }

        let mark_special_links = false;
        if (typeof this.options.mark_special_links === "string") {
            mark_special_links =
                this.options.mark_special_links.toLowerCase() === "true";
        } else if (typeof this.options.mark_special_links === "boolean") {
            mark_special_links = this.options.mark_special_links;
        }

        if (mark_special_links) {
            import("./markspeciallinks.scss");
        }

        // All links with an http href (without the link-plain class), not within this site,
        // and no img children should be wrapped in a link-external span
        const url = window.location.protocol + "//" + window.location.host;
        const links = this.el.querySelectorAll(
            `a[href]:not(.link-plain):not([href^="${url}"]):not([href^="#"])`
        );
        //:not(:has(img))
        for (const link of links) {
            let link_url;
            try {
                link_url = new URL(link.getAttribute("href"));
            } catch (e) {
                if (e instanceof TypeError) {
                    // Not a valid URL.
                    // Ignore and continue.
                    continue;
                }
            }
            if (open_new_window && link_url.protocol.startsWith("http")) {
                link.setAttribute("target", "_blank");
                link.setAttribute("rel", "noopener");
            }

            if (mark_special_links) {
                const icon_name =
                    this.protocol_icon_map[link_url.protocol.split(":")[0]];
                if (icon_name) {
                    const icon = await utils.resolveIcon(icon_name);
                    const icon_el = dom.create_from_string(icon);
                    icon_el.classList.add("markspeciallinks__icon");
                    link.parentNode.insertBefore(icon_el, link);
                }
            }
        }
    },
});
<commit_msg>fix(pat markspeciallinks): fix tests<commit_after>import Base from "@patternslib/patternslib/src/core/base";
import dom from "@patternslib/patternslib/src/core/dom";
import utils from "../../core/utils";

export default Base.extend({
    name: "markspeciallinks",
    trigger: ".pat-markspeciallinks",
    parser: "mockup",

    defaults: {
        external_links_open_new_window: false,
        mark_special_links: true,
    },

    protocol_icon_map: {
        // For a list of supported default protocol hander, see:
        // https://developer.mozilla.org/en-US/docs/Web/API/Navigator/registerProtocolHandler#permitted_schemes
        https: "link-45deg",
        http: "link-45deg",
        ftp: "cloud-download", // deprecated
        callto: "telephone", // non-standard for skype
        bitcoin: "credit-card", // no bitcoin icon yet
        geo: "geo-alt",
        im: "chat",
        irc: "chat",
        ircs: "chat",
        magnet: "link-45deg",
        mailto: "envelope",
        mms: "chat",
        news: "newspaper",
        nntp: "newspaper",
        openpgp4fpr: "key",
        sip: "telephone",
        sms: "chat",
        smsto: "chat",
        ssh: "lock",
        tel: "telephone",
        urn: "link-45deg",
        webcal: "calendar",
        wtai: "telephone",
        xmpp: "chat",
    },

    async init() {
        // first make external links open in a new window, afterwards do the
        // normal plone link wrapping in only the content area

        let open_new_window = false;
        if (typeof this.options.external_links_open_new_window === "string") {
            open_new_window =
                this.options.external_links_open_new_window.toLowerCase() === "true";
        } else if (typeof this.options.external_links_open_new_window === "boolean") {
            open_new_window = this.options.external_links_open_new_window;
        }

        let mark_special_links = false;
        if (typeof this.options.mark_special_links === "string") {
            mark_special_links =
                this.options.mark_special_links.toLowerCase() === "true";
        } else if (typeof this.options.mark_special_links === "boolean") {
            mark_special_links = this.options.mark_special_links;
        }

        if (mark_special_links) {
            import("./markspeciallinks.scss");
        }

        // All links with an http href (without the link-plain class), not within this site,
        // and no img children should be wrapped in a link-external span
        const url = window.location.protocol + "//" + window.location.host;
        const links = this.el.querySelectorAll(
            `a[href]:not(.link-plain):not([href^="${url}"]):not([href^="#"])`
        );
        //:not(:has(img))
        for (const link of links) {
            let link_url;
            try {
                link_url = new URL(link.getAttribute("href"));
            } catch (e) {
                // Not a valid URL.
                // Ignore and continue.
                continue;
            }

            if (open_new_window && link_url.protocol.startsWith("http")) {
                link.setAttribute("target", "_blank");
                link.setAttribute("rel", "noopener");
            }

            if (mark_special_links) {
                const icon_name =
                    this.protocol_icon_map[link_url.protocol.split(":")[0]];
                if (icon_name) {
                    const icon = await utils.resolveIcon(icon_name);
                    const icon_el = dom.create_from_string(icon);
                    icon_el.querySelector("svg").classList.add("markspeciallinks__icon");
                    link.parentNode.insertBefore(icon_el, link);
                }
            }
        }
    },
});
<|endoftext|>


<commit_before>/***
|''Name''|TiddlySpacePublishingCommands|
|''Version''|0.8.3|
|''Status''|@@beta@@|
|''Description''|toolbar commands for drafting and publishing|
|''Author''|Jon Robson|
|''Source''|http://github.com/TiddlySpace/tiddlyspace/raw/master/src/plugins/TiddlySpacePublishingCommands.js|
|''Requires''|TiddlySpaceConfig|
!Usage
Provides changeToPrivate, changeToPublic and saveDraft commands
Provides TiddlySpacePublisher macro.
{{{<<TiddlySpacePublisher type:private>>}}} make lots of private tiddlers public.
{{{<<TiddlySpacePublisher type:public>>}}} make lots of public tiddlers public.
!TODO
* add public argument?
!Code
***/
//{{{
(function($) {

var tiddlyspace = config.extensions.tiddlyspace;
var currentSpace = tiddlyspace.currentSpace.name;
var originMacro = config.macros.tiddlerOrigin;
tiddlyspace.getTiddlerStatusType = function(tiddler) {
	var isShadow = store.isShadowTiddler(tiddler.title);
	var exists = store.tiddlerExists(tiddler.title);
	if(isShadow && !exists) {
		return "shadow";
	} else if(!exists) {
		return "missing";
	} else {
		var bag = tiddler.fields["server.bag"];
		var currentSpace = tiddlyspace.currentSpace.name;
		var privateBag = "%0_private".format([currentSpace]);
		var publicBag = "%0_public".format([currentSpace]);
		if(bag == privateBag) {
			return "private";
		} else if (bag == publicBag) {
			return "public";
		} else {
			return "external";
		}
	}
};

var cmd = config.commands.publishTiddler = {
	text: "make public",
	tooltip: "Change this private tiddler into a public tiddler",
	errorMsg: "Error publishing %0: %1",

	isEnabled: function(tiddler) {
		var type = tiddlyspace.getTiddlerStatusType(tiddler);
		if(!readOnly && type == "private") {
			return true;
		} else {
			return false;
		}
	},
	handler: function(ev, src, title) {
		var tiddler = store.getTiddler(title);
		if(tiddler) {
			var newBag = cmd.toggleBag(tiddler.fields["server.bag"]);
			this.moveTiddler(tiddler, {
				title: tiddler.fields["publish.name"] || tiddler.title,
				fields: { "server.bag": newBag }
			});
		}
	},
	toggleBag: function(bag, to) {
		var newBag;
		if(typeof bag != typeof "") {
			var tiddler = bag;
			bag = tiddler.fields["server.bag"];
		}
		if(bag.indexOf("_private") > -1) { // should make use of endsWith
			to = to ? to : "public";
			newBag = bag.replace("_private", "_" + to);
		} else {
			to = to ? to : "private";
			newBag = bag.replace("_public", "_" + to);
		}
		return newBag;
	},
	copyTiddler: function(title, newTitle, newBag, callback) {
		var original = store.getTiddler(title);
		newTitle = newTitle ? newTitle : title;
		var adaptor = original.getAdaptor();
		var publish = function(original, callback) {
			var tiddler = $.extend(new Tiddler(newTitle), original);
			tiddler.fields = $.extend({}, original.fields, {
				"server.bag": newBag,
				"server.workspace": "bags/%0".format([newBag]),
				"server.page.revision": "false"
			});
			delete tiddler.fields["server.title"];
			tiddler.title = newTitle;
			adaptor.putTiddler(tiddler, null, null, callback);
		};
		publish(original, callback);
	},
	moveTiddler: function(tiddler, newTiddler, callback) {
			var info = {
			copyContext: {},
			deleteContext: {}
		};
		var _dirty = store.isDirty();
		var adaptor = tiddler.getAdaptor();
		var newTitle = newTiddler.title;
		var oldTitle = tiddler.title;
		delete tiddler.fields["server.workspace"];
		var oldBag = tiddler.fields["server.bag"];
		var newBag = newTiddler.fields["server.bag"];
		var newWorkspace = "bags/%0".format([newBag]);
		cmd.copyTiddler(oldTitle, newTitle, newBag, function(ctx) {
				info.copyContext = ctx;
				var context = {
					tiddler: tiddler,
					workspace: newWorkspace
				};
				store.addTiddler(ctx.tiddler);
				tiddler.title = oldTitle; // for cases where a rename occurs
				if(ctx.status) { // only do if a success
					if(oldBag != newBag) {
						adaptor.deleteTiddler(tiddler, context, {}, function(ctx) {
							info.deleteContext = ctx;
							var el;
							if(tiddler) {
								tiddler.fields["server.workspace"] = newWorkspace;
								tiddler.fields["server.bag"] = newBag;
							}
							el = el ? el : story.refreshTiddler(oldTitle, null, true);
							if(oldTitle != newTitle) {
								store.deleteTiddler(oldTitle);
								refreshDisplay();
							}
							if(el) {
								story.displayTiddler(el, newTitle);
							}
							if(oldTitle != newTitle) {
								story.closeTiddler(oldTitle);
							}
							if(callback) {
								callback(info);
							}
							store.setDirty(_dirty);
							story.refreshTiddler(newTitle, null, true); // for drafts
						});
					} else {
						if(callback) {
							callback(info);
						}
						story.refreshTiddler(newTitle, null, true);
					}
				}
		});
	}
};

config.commands.changeToPrivate = {
	text: "make private",
	tooltip: "turn this public tiddler into a private tiddler",
	isEnabled: function(tiddler) {
		var type = tiddlyspace.getTiddlerStatusType(tiddler);
		if(!readOnly && type == "public") {
			return true;
		} else {
			return false;
		}
	},
	handler: function(event, src, title) {
		var tiddler = store.getTiddler(title);
		var newBag = cmd.toggleBag(tiddler, "private");
		var newTiddler = { title: title, fields: { "server.bag": newBag }};
		cmd.moveTiddler(tiddler, newTiddler);
	}
};
config.commands.changeToPublic = config.commands.publishTiddler;

/* Save as draft command */
var saveDraftCmd = config.commands.saveDraft = {
	text: "save draft",
	tooltip: "Save as a private draft",
	isEnabled: function(tiddler) {
		var type = tiddlyspace.getTiddlerStatusType(tiddler);
		if(!readOnly && type == "public") {
			return true;
		} else {
			return false;
		}
	},
	getDraftTitle: function(title) {
		var draftTitle;
		var draftNum = "";
		while(!draftTitle) {
			var suggestedTitle = "%0 [draft%1]".format([title, draftNum]);
			if(store.getTiddler(suggestedTitle)) {
				draftNum = !draftNum ? 2 : draftNum + 1;
			} else {
				draftTitle = suggestedTitle;
			}
		}
		return draftTitle;
	},
	createDraftTiddler: function(title, gatheredFields) {
		var tiddler = store.getTiddler(title);
		var draftTitle = saveDraftCmd.getDraftTitle(title);
		var draftTiddler = new Tiddler(draftTitle);
		if(tiddler) {
			$.extend(true, draftTiddler, tiddler);
		} else {
			$.extend(draftTiddler.fields, config.defaultCustomFields);
		}
		for(var fieldName in gatheredFields) {
			if(TiddlyWiki.isStandardField(fieldName)) {
				draftTiddler[fieldName] = gatheredFields[fieldName];
			} else {
				draftTiddler.fields[fieldName] = gatheredFields[fieldName];
			}
		}
		var currentSpace = tiddlyspace.currentSpace.name;
		var privateBag = "%0_private".format([currentSpace]);
		var privateWorkspace = "bags/%0".format([privateBag]);
		draftTiddler.title = draftTitle;
		draftTiddler.fields["publish.name"] = title;
		draftTiddler.fields["server.workspace"] = privateWorkspace;
		draftTiddler.fields["server.bag"] = privateBag;
		draftTiddler.fields["server.title"] = draftTitle;
		draftTiddler.fields["server.page.revision"] = "false";
		delete draftTiddler.fields["server.etag"];
		return draftTiddler;
	},
	handler: function(ev, src, title) {
		var tiddler = store.getTiddler(title); // original tiddler
		var tidEl = story.getTiddler(title);
		var uiFields = {};
		story.gatherSaveFields(tidEl, uiFields);
		var tid = saveDraftCmd.createDraftTiddler(title, uiFields);
		tid = store.saveTiddler(tid.title, tid.title, tid.text, tid.modifier,
			new Date(), tid.tags, tid.fields);
		autoSaveChanges(null, [tid]);
		story.closeTiddler(title);
		story.displayTiddler(src, title);
		story.displayTiddler(src, tid.title);
	}
};

var macro = config.macros.TiddlySpacePublisher = {
	locale: {
		title: "Batch Publisher",
		changeStatusLabel: "Make %0",
		noTiddlersText: "No tiddlers to publish",
		changeStatusPrompt: "Make all the selected tiddlers %0.",
		description: "Change tiddlers from %0 to %1 in this space"
	},

	listViewTemplate: {
		columns: [
			{ name: "Selected", field: "Selected", rowName: "title", type: "Selector" },
			{ name: "Tiddler", field: "tiddler", title: "Tiddler", type: "Tiddler" },
			{ name: "Status", field: "status", title: "Status", type: "WikiText" }
		],
		rowClasses: []
	},

	changeStatus: function(tiddlers, status, callback) { // this is what is called when you click the publish button
		var cmd = config.commands.publishTiddler;
		var publicBag;
		for(var i = 0; i < tiddlers.length; i++) {
			var tiddler = tiddlers[i];
			var newTiddler = {
				title: tiddler.title,
				fields: { "server.bag": cmd.toggleBag(tiddler, status) }
			};
			config.commands.publishTiddler.moveTiddler(tiddler, newTiddler, callback);
		}
	},
	getMode: function(paramString) {
		var params = paramString.parseParams("anon")[0];
		var status = params.type ?
			(["public", "private"].contains(params.type[0]) ? params.type[0] : "private") :
			"private";
		var newStatus = status == "public" ? "private" : "public";
		return [status, newStatus];
	},
	handler: function(place, macroName, params, wikifier, paramString, tiddler) {
		tiddler = tiddler ? tiddler : store.getTiddlers()[0];
		var wizard = new Wizard();
		var locale = macro.locale;
		var status = macro.getMode(paramString);
		wizard.createWizard(place, locale.title);
		wizard.addStep(macro.locale.description.format([status[0], status[1]]), '<input type="hidden" name="markList" />');
		var markList = wizard.getElement("markList");
		var listWrapper = $("<div />").addClass("batchPublisher").
			attr("refresh", "macro").attr("macroName", macroName).attr("params", paramString)[0];
		markList.parentNode.insertBefore(listWrapper, markList);
		$.data(listWrapper, "wizard", wizard);
		macro.refresh(listWrapper)
	},
	getCheckedTiddlers: function(listWrapper, titlesOnly) {
		var tiddlers = [];
		$(".chkOptionInput[rowName]:checked", listWrapper).each(function(i, el) {
			var title = $(el).attr("rowName");
			if(titlesOnly) {
				tiddlers.push(title);
			} else {
				tiddlers.push(store.getTiddler(title));
			}
		});
		return tiddlers;
	},
	refresh: function(listWrapper) {
		var checked = macro.getCheckedTiddlers(listWrapper, true);
		var paramString = $(listWrapper).empty().attr("params");
		var wizard = $.data(listWrapper, "wizard");
		var locale = macro.locale;
		var params = paramString.parseParams("anon")[0];
		var publishCandidates = [];
		var tiddlers = params.filter ? store.filterTiddlers(params.filter[0]) : store.getTiddlers("title", "excludePublisher");
		var status = macro.getMode(paramString);
		var fromBag = "%0_%1".format([currentSpace, status[0]]);

		// TODO: would be good if filterTiddlers could do the bag checking.
		var enabled = [];
		for(var i = 0; i < tiddlers.length; i++) {
			var tiddler = tiddlers[i];
			var bag = tiddler.fields["server.bag"];
			if(bag == fromBag) {
					publishCandidates.push({ title: tiddler.title, tiddler: tiddler, status: status[0]});
					if(checked.contains(tiddler.title)) {
						enabled.push("[rowname=%0]".format(tiddler.title));
					}
			}
		}

		if(publishCandidates.length === 0) {
			createTiddlyElement(listWrapper, "em", null, null, locale.noTiddlersText);
		} else {
			var listView = ListView.create(listWrapper, publishCandidates, macro.listViewTemplate);
			wizard.setValue("listView", listView);
			var btnHandler = function(ev) {
				var tiddlers = macro.getCheckedTiddlers(listWrapper)
				var callback = function(status) {
					$(".batchPublisher").each(function(i, el) {
						macro.refresh(el);
					});
				};
				macro.changeStatus(tiddlers, status[1], callback);
			};
			wizard.setButtons([
				{ caption: locale.changeStatusLabel.format([status[1]]), tooltip: locale.changeStatusPrompt.format([status[1]]),
					onClick: btnHandler }
			]);
			$(enabled.join(",")).attr("checked", true); // retain what was checked before.
		}
	}
};

})(jQuery);
//}}}
<commit_msg>improved refresh efficiency for publishing commands<commit_after>/***
|''Name''|TiddlySpacePublishingCommands|
|''Version''|0.8.3|
|''Status''|@@beta@@|
|''Description''|toolbar commands for drafting and publishing|
|''Author''|Jon Robson|
|''Source''|http://github.com/TiddlySpace/tiddlyspace/raw/master/src/plugins/TiddlySpacePublishingCommands.js|
|''Requires''|TiddlySpaceConfig|
!Usage
Provides changeToPrivate, changeToPublic and saveDraft commands
Provides TiddlySpacePublisher macro.
{{{<<TiddlySpacePublisher type:private>>}}} make lots of private tiddlers public.
{{{<<TiddlySpacePublisher type:public>>}}} make lots of public tiddlers public.
!TODO
* add public argument?
!Code
***/
//{{{
(function($) {

var tiddlyspace = config.extensions.tiddlyspace;
var currentSpace = tiddlyspace.currentSpace.name;
var originMacro = config.macros.tiddlerOrigin;

tiddlyspace.getTiddlerStatusType = function(tiddler) {
	var isShadow = store.isShadowTiddler(tiddler.title);
	var exists = store.tiddlerExists(tiddler.title);
	if(isShadow && !exists) {
		return "shadow";
	} else if(!exists) {
		return "missing";
	} else {
		var bag = tiddler.fields["server.bag"];
		var privateBag = "%0_private".format(currentSpace);
		var publicBag = "%0_public".format(currentSpace);
		if(bag == privateBag) {
			return "private";
		} else if (bag == publicBag) {
			return "public";
		} else {
			return "external";
		}
	}
};

var cmd = config.commands.publishTiddler = {
	text: "make public",
	tooltip: "Change this private tiddler into a public tiddler",
	errorMsg: "Error publishing %0: %1",

	isEnabled: function(tiddler) {
		var type = tiddlyspace.getTiddlerStatusType(tiddler);
		if(!readOnly && type == "private") {
			return true;
		} else {
			return false;
		}
	},
	handler: function(ev, src, title) {
		var tiddler = store.getTiddler(title);
		if(tiddler) {
			var newBag = cmd.toggleBag(tiddler.fields["server.bag"]);
			this.moveTiddler(tiddler, {
				title: tiddler.fields["publish.name"] || tiddler.title,
				fields: { "server.bag": newBag }
			});
		}
	},
	toggleBag: function(bag, to) {
		var newBag;
		if(typeof bag != typeof "") {
			var tiddler = bag;
			bag = tiddler.fields["server.bag"];
		}
		if(bag.indexOf("_private") > -1) { // should make use of endsWith
			to = to ? to : "public";
			newBag = bag.replace("_private", "_" + to);
		} else {
			to = to ? to : "private";
			newBag = bag.replace("_public", "_" + to);
		}
		return newBag;
	},
	copyTiddler: function(title, newTitle, newBag, callback) {
		var original = store.getTiddler(title);
		newTitle = newTitle ? newTitle : title;
		var adaptor = original.getAdaptor();
		var publish = function(original, callback) {
			var tiddler = $.extend(new Tiddler(newTitle), original);
			tiddler.fields = $.extend({}, original.fields, {
				"server.bag": newBag,
				"server.workspace": "bags/%0".format(newBag),
				"server.page.revision": "false"
			});
			delete tiddler.fields["server.title"];
			tiddler.title = newTitle;
			adaptor.putTiddler(tiddler, null, null, callback);
		};
		publish(original, callback);
	},
	moveTiddler: function(tiddler, newTiddler, callback) {
			var info = {
			copyContext: {},
			deleteContext: {}
		};
		var _dirty = store.isDirty();
		var adaptor = tiddler.getAdaptor();
		var newTitle = newTiddler.title;
		var oldTitle = tiddler.title;
		delete tiddler.fields["server.workspace"];
		var oldBag = tiddler.fields["server.bag"];
		var newBag = newTiddler.fields["server.bag"];
		var newWorkspace = "bags/%0".format(newBag);
		cmd.copyTiddler(oldTitle, newTitle, newBag, function(ctx) {
				info.copyContext = ctx;
				var context = {
					tiddler: tiddler,
					workspace: newWorkspace
				};
				store.addTiddler(ctx.tiddler);
				tiddler.title = oldTitle; // for cases where a rename occurs
				if(ctx.status) { // only do if a success
					if(oldBag != newBag) {
						adaptor.deleteTiddler(tiddler, context, {}, function(ctx) {
							info.deleteContext = ctx;
							var el;
							if(tiddler) {
								tiddler.fields["server.workspace"] = newWorkspace;
								tiddler.fields["server.bag"] = newBag;
							}
							el = el ? el : story.refreshTiddler(oldTitle, null, true);
							if(oldTitle != newTitle) {
								store.deleteTiddler(oldTitle);
								store.notify(oldTitle, true);
							}
							if(el) {
								story.displayTiddler(el, newTitle);
							}
							if(oldTitle != newTitle) {
								story.closeTiddler(oldTitle);
							}
							if(callback) {
								callback(info);
							}
							store.setDirty(_dirty);
							story.refreshTiddler(newTitle, null, true); // for drafts
						});
					} else {
						if(callback) {
							callback(info);
						}
						story.refreshTiddler(newTitle, null, true);
					}
				}
		});
	}
};

config.commands.changeToPrivate = {
	text: "make private",
	tooltip: "turn this public tiddler into a private tiddler",
	isEnabled: function(tiddler) {
		var type = tiddlyspace.getTiddlerStatusType(tiddler);
		if(!readOnly && type == "public") {
			return true;
		} else {
			return false;
		}
	},
	handler: function(event, src, title) {
		var tiddler = store.getTiddler(title);
		var newBag = cmd.toggleBag(tiddler, "private");
		var newTiddler = { title: title, fields: { "server.bag": newBag }};
		cmd.moveTiddler(tiddler, newTiddler);
	}
};
config.commands.changeToPublic = config.commands.publishTiddler;

/* Save as draft command */
var saveDraftCmd = config.commands.saveDraft = {
	text: "save draft",
	tooltip: "Save as a private draft",
	isEnabled: function(tiddler) {
		var type = tiddlyspace.getTiddlerStatusType(tiddler);
		if(!readOnly && type == "public") {
			return true;
		} else {
			return false;
		}
	},
	getDraftTitle: function(title) {
		var draftTitle;
		var draftNum = "";
		while(!draftTitle) {
			var suggestedTitle = "%0 [draft%1]".format(title, draftNum);
			if(store.getTiddler(suggestedTitle)) {
				draftNum = !draftNum ? 2 : draftNum + 1;
			} else {
				draftTitle = suggestedTitle;
			}
		}
		return draftTitle;
	},
	createDraftTiddler: function(title, gatheredFields) {
		var tiddler = store.getTiddler(title);
		var draftTitle = saveDraftCmd.getDraftTitle(title);
		var draftTiddler = new Tiddler(draftTitle);
		if(tiddler) {
			$.extend(true, draftTiddler, tiddler);
		} else {
			$.extend(draftTiddler.fields, config.defaultCustomFields);
		}
		for(var fieldName in gatheredFields) {
			if(TiddlyWiki.isStandardField(fieldName)) {
				draftTiddler[fieldName] = gatheredFields[fieldName];
			} else {
				draftTiddler.fields[fieldName] = gatheredFields[fieldName];
			}
		}
		var privateBag = "%0_private".format(currentSpace);
		var privateWorkspace = "bags/%0".format(privateBag);
		draftTiddler.title = draftTitle;
		draftTiddler.fields["publish.name"] = title;
		draftTiddler.fields["server.workspace"] = privateWorkspace;
		draftTiddler.fields["server.bag"] = privateBag;
		draftTiddler.fields["server.title"] = draftTitle;
		draftTiddler.fields["server.page.revision"] = "false";
		delete draftTiddler.fields["server.etag"];
		return draftTiddler;
	},
	handler: function(ev, src, title) {
		var tiddler = store.getTiddler(title); // original tiddler
		var tidEl = story.getTiddler(title);
		var uiFields = {};
		story.gatherSaveFields(tidEl, uiFields);
		var tid = saveDraftCmd.createDraftTiddler(title, uiFields);
		tid = store.saveTiddler(tid.title, tid.title, tid.text, tid.modifier,
			new Date(), tid.tags, tid.fields);
		autoSaveChanges(null, [tid]);
		story.closeTiddler(title);
		story.displayTiddler(src, title);
		story.displayTiddler(src, tid.title);
	}
};

var macro = config.macros.TiddlySpacePublisher = {
	locale: {
		title: "Batch Publisher",
		changeStatusLabel: "Make %0",
		noTiddlersText: "No tiddlers to publish",
		changeStatusPrompt: "Make all the selected tiddlers %0.",
		description: "Change tiddlers from %0 to %1 in this space"
	},

	listViewTemplate: {
		columns: [
			{ name: "Selected", field: "Selected", rowName: "title", type: "Selector" },
			{ name: "Tiddler", field: "tiddler", title: "Tiddler", type: "Tiddler" },
			{ name: "Status", field: "status", title: "Status", type: "WikiText" }
		],
		rowClasses: []
	},

	changeStatus: function(tiddlers, status, callback) { // this is what is called when you click the publish button
		var cmd = config.commands.publishTiddler;
		var publicBag;
		for(var i = 0; i < tiddlers.length; i++) {
			var tiddler = tiddlers[i];
			var newTiddler = {
				title: tiddler.title,
				fields: { "server.bag": cmd.toggleBag(tiddler, status) }
			};
			config.commands.publishTiddler.moveTiddler(tiddler, newTiddler, callback);
		}
	},
	getMode: function(paramString) {
		var params = paramString.parseParams("anon")[0];
		var status = params.type ?
			(["public", "private"].contains(params.type[0]) ? params.type[0] : "private") :
			"private";
		var newStatus = status == "public" ? "private" : "public";
		return [status, newStatus];
	},
	handler: function(place, macroName, params, wikifier, paramString, tiddler) {
		tiddler = tiddler ? tiddler : store.getTiddlers()[0];
		var wizard = new Wizard();
		var locale = macro.locale;
		var status = macro.getMode(paramString);
		wizard.createWizard(place, locale.title);
		wizard.addStep(macro.locale.description.format(status[0], status[1]),
			'<input type="hidden" name="markList" />');
		var markList = wizard.getElement("markList");
		var listWrapper = $("<div />").addClass("batchPublisher").
			attr("refresh", "macro").attr("macroName", macroName).attr("params", paramString)[0];
		markList.parentNode.insertBefore(listWrapper, markList);
		$.data(listWrapper, "wizard", wizard);
		macro.refresh(listWrapper)
	},
	getCheckedTiddlers: function(listWrapper, titlesOnly) {
		var tiddlers = [];
		$(".chkOptionInput[rowName]:checked", listWrapper).each(function(i, el) {
			var title = $(el).attr("rowName");
			if(titlesOnly) {
				tiddlers.push(title);
			} else {
				tiddlers.push(store.getTiddler(title));
			}
		});
		return tiddlers;
	},
	refresh: function(listWrapper) {
		var checked = macro.getCheckedTiddlers(listWrapper, true);
		var paramString = $(listWrapper).empty().attr("params");
		var wizard = $.data(listWrapper, "wizard");
		var locale = macro.locale;
		var params = paramString.parseParams("anon")[0];
		var publishCandidates = [];
		var tiddlers = params.filter ? store.filterTiddlers(params.filter[0]) : store.getTiddlers("title", "excludePublisher");
		var status = macro.getMode(paramString);
		var fromBag = "%0_%1".format(currentSpace, status[0]);

		// TODO: would be good if filterTiddlers could do the bag checking.
		var enabled = [];
		for(var i = 0; i < tiddlers.length; i++) {
			var tiddler = tiddlers[i];
			var bag = tiddler.fields["server.bag"];
			if(bag == fromBag) {
					publishCandidates.push({ title: tiddler.title, tiddler: tiddler, status: status[0]});
					if(checked.contains(tiddler.title)) {
						enabled.push("[rowname=%0]".format(tiddler.title));
					}
			}
		}

		if(publishCandidates.length === 0) {
			createTiddlyElement(listWrapper, "em", null, null, locale.noTiddlersText);
		} else {
			var listView = ListView.create(listWrapper, publishCandidates, macro.listViewTemplate);
			wizard.setValue("listView", listView);
			var btnHandler = function(ev) {
				var tiddlers = macro.getCheckedTiddlers(listWrapper)
				var callback = function(status) {
					$(".batchPublisher").each(function(i, el) {
						macro.refresh(el);
					});
				};
				macro.changeStatus(tiddlers, status[1], callback);
			};
			wizard.setButtons([{
				caption: locale.changeStatusLabel.format(status[1]),
				tooltip: locale.changeStatusPrompt.format(status[1]),
				onClick: btnHandler
			}]);
			$(enabled.join(",")).attr("checked", true); // retain what was checked before.
		}
	}
};

})(jQuery);
//}}}
<|endoftext|>


<commit_before>// Trie data structure code is adapted from Ben Vallon's Computer Science in Javascript #data-structures series
// His code can be found at https://github.com/benoitvallon/computer-science-in-javascript/blob/master/data-structures-in-javascript/trie.js

// Node object creation. When called, creates Node object with given properties.
function Node(data){
	this.data = data;
	this.isWord = false;
	this.prefixes = 0;
	this.children = {};
}

// Create a new trie structure with a root node containing and empty string.
function Trie(){
	this.root = new Node('');
}

// Defines trie method for adding a word to the structure.
Trie.prototype.add = function(node, word) {
  if(!node || !word) {
    return null;
  }
  node.prefixes++;
  var letter = word.charAt(0);
// Check if the node already has a child with the given letter. If no child is found for that letter, create a new one and add it to the previous node's child property.
// Important to note that although children was originally declared as an empty array, by using a named index and not a numerical, Javascript automatically converts to an object.
  var child = node.children[letter];
  if(!child) {
	    if (letter.match(/^(a|b|c|e|g|i|l|o|s|t)$/)){
			switch (letter){
				case 'a':
					child = new Node('a');
					node.children['a'] = child;
					this.addRecursive(child, word);
					child = new Node('@');
					node.children['@'] = child;
					this.addRecursive(child, word);
					child = new Node('4');
					node.children['4'] = child;
					this.addRecursive(child, word);
					break;
				case 'b':
					child = new Node('b');
					node.children['b'] = child;
					this.addRecursive(child, word);
					child = new Node('6');
					node.children['6'] = child;
					this.addRecursive(child, word);
					break;
				case 'c':
					child = new Node('c');
					node.children['c'] = child;
					this.addRecursive(child, word);
					child = new Node('(');
					node.children['('] = child;
					this.addRecursive(child, word);
					break;
				case 'e':
					child = new Node('e');
					node.children['e'] = child;
					this.addRecursive(child, word);
					child = new Node('3');
					node.children['3'] = child;
					this.addRecursive(child, word);
					break;
				case 'g':
					child = new Node('g');
					node.children['g'] = child;
					this.addRecursive(child, word);
					child = new Node('9');
					node.children['9'] = child;
					this.addRecursive(child, word);
					break;
				case 'i':
					child = new Node('i');
					node.children['i'] = child;
					this.addRecursive(child, word);
					child = new Node('1');
					node.children['1'] = child;
					this.addRecursive(child, word);
					child = new Node('!');
					node.children['!'] = child;
					this.addRecursive(child, word);
					break;
				case 'l':
					child = new Node('l');
					node.children['l'] = child;
					this.addRecursive(child, word);
					child = new Node('1');
					node.children['1'] = child;
					this.addRecursive(child, word);
					child = new Node('!');
					node.children['!'] = child;
					this.addRecursive(child, word);
					break;
				case 'o':
					child = new Node('o');
					node.children['o'] = child;
					this.addRecursive(child, word);
					child = new Node('0');
					node.children['0'] = child;
					this.addRecursive(child, word);
					break;
				case 's':
					child = new Node('s');
					node.children['s'] = child;
					this.addRecursive(child, word);
					child = new Node('5');
					node.children['5'] = child;
					this.addRecursive(child, word);
					break;
				case 't':
					child = new Node('t');
					node.children['t'] = child;
					this.addRecursive(child, word);
					child = new Node('+');
					node.children['+'] = child;
					this.addRecursive(child, word);
					child = new Node('7');
					node.children['7'] = child;
					this.addRecursive(child, word);
					break;
				default:
					alert('No data matched. You should not be seeing this.')
			}
		}else{
			child = new Node(letter);
			node.children[letter] = child;
		}
  }

this.addRecursive(child, word);
 };
// Determine how many characters are left in word to be added. If none, set isWord flag to true and complete. Else, recursively call add with new child node and rest of word.

//For loop needed for each created Node
Trie.prototype.addRecursive = function(child, word){
  var remainder = word.substring(1);
  if(!remainder) {
    child.isWord = true;
  }
  this.add(child, remainder);
}

// Debug function to list all words stored in the trie.
Trie.prototype.getWords = function() {
  var words = [];
  var word = '';
  this._getWords(this.root, words, words, word);
  return words;
};
Trie.prototype._getWords = function(node, words, word) {
  for(var child in node.children) {
    if(node.children.hasOwnProperty(child)) {
      word += child;
      if (node.children[child].isWord) {
        words.push(word);
      }
      this._getWords(node.children[child], words, word);
      word = word.substring(0, word.length - 1);
    }
  }
};
// Trie method for searching the structure for a particular word.
// The original trie.contains method described by Ben Vallon is only effective for exact matching. For our project, the matching word may be located inside of a longer string.
// This meant .contains required modification to search the entirety of a string for a keyword.
var fullWord ="";
Trie.prototype.contains = function(node, word) {

	//alert(node.data);
  if(!node || !word) {
	  //alert("NO TRIE OR WORD");
    return false;
  }
  var letter = word.charAt(0);
  var child = node.children[letter];
  if(child) {
    var remainder = word.substring(1);
    if(child.isWord) {
		fullWord+=child.data.toString();
		var finalWord = fullWord;
		fullWord="";
      return finalWord;
    } else {
		fullWord+=child.data.toString();

      return this.contains(child, remainder);
    }
// The original .contains method simply terminates the search if there a node has no children containing the target letter.
// This doesn't work for our use case as the keyword may lie after an arbitrary string not contained in the trie.
  } else {
	// If there is no branch off root with the current letter, move to the next letter of the target string.
	if (!remainder){
		fullWord="";
		return this.contains(this.root, word.substring(1));
	// If there is no branch off the current node with the current letter but the target string has not been fully searched, restart the search at root from the current location in the target string.
	}  else if (remainder.substring(1).length > 0){
		return this.contains(this.root, remainder.substring(1));
	// The full target string has been searched and there was no hit. This means the target string truely doesn't contain any keywords.
	}  else{
		//alert("full phrase test");
		return false;
	}

  }
};

Trie.prototype.remove = function(word){
	if(!this.root){
		alert("NO ROOT");
		return;
	}
	if(this.contains(this.root,word)){
		this._removeNode(this.root, word);
	}
};

Trie.prototype._removeNode = function(node, word){
	if(!node || !word){
		alert("NO ROOT OR WORD");
		return;
	}
	node.prefixes--;
	var letter = word.charAt(0);
	var child = node.children[letter];
	if(child){
		if (letter.match(/^(a|b|c|e|g|i|l|o|s|t)$/)){
			switch(letter){
				case 'a':
					letter = 'a';
					this.recursiveRemove(letter,word,node,child);
					letter = '@';
					this.recursiveRemove(letter,word,node,child);
					letter = '4';
					this.recursiveRemove(letter,word,node,child);
					break;
				case 'i':
					letter = 'i';
					this.recursiveRemove(letter,word,node,child);
					letter = '1';
					this.recursiveRemove(letter,word,node,child);
					letter = '!';
					this.recursiveRemove(letter,word,node,child);
					break;
				default:
					alert("DEFAULT CASE");
			}

		} else{
		var remainder = word.substring(1);
		if(remainder){
			if(child.prefixes === 1){
				delete node.children[letter];
			} else{
				this._removeNode(child, remainder);
			}
		} else{
			if(child.prefixes === 0){
				delete node.children[letter];
			} else{
				child.isWord = false;
			}
		}
		}
	}
};

Trie.prototype.recursiveRemove = function(letter, word, node, child){
	var remainder = word.substring(1);
	if(remainder){
		if(child.prefixes === 1){
			delete node.children[letter];
		} else{
			this._removeNode(child, remainder);
		}
	} else{
		if(child.prefixes === 0){
			delete node.children[letter];
		} else{
			child.isWord = false;
		}
	}
}
Trie.prototype.printByLevel = function() {
  if(!this.root) {
    return console.log('No root node found');
  }
  var newline = new Node('\n');
  var queue = [this.root, newline];
  var string = '';
  while(queue.length) {
    var node = queue.shift();
    string += node.data.toString() + (node.data !== '\n' ? ' ' : '');
    if(node === newline && queue.length) {
      queue.push(newline);
    }
    for(var child in node.children) {
      if(node.children.hasOwnProperty(child)) {
        queue.push(node.children[child]);
      }
    }
  }
  console.log(string.trim());
};
// Fetch stored data in Chrome storage. Once completed, call buildTrie and pass retrieved data.
function trieData(){
	chrome.storage.sync.get("userdata", buildTrie);
}

// Create trie structure with fetched data from Chrome storage.
function buildTrie(data){
	trie = new Trie();
	for (var x = 0; x < data.userdata.length; x++){
			var value = (data.userdata[x]);
			trie.add(trie.root,data.userdata[x].toString());
		}
// Debug code to list contents of trie.
	//alert(trie.getWords());
	//alert("Does trie contain \"testaidantest\"?" + trie.contains("testaidantest"));
}
var trie;<commit_msg>Expanded trie.remove substitution support<commit_after>// Trie data structure code is adapted from Ben Vallon's Computer Science in Javascript #data-structures series
// His code can be found at https://github.com/benoitvallon/computer-science-in-javascript/blob/master/data-structures-in-javascript/trie.js

// Node object creation. When called, creates Node object with given properties.
function Node(data){
	this.data = data;
	this.isWord = false;
	this.prefixes = 0;
	this.children = {};
}

// Create a new trie structure with a root node containing and empty string.
function Trie(){
	this.root = new Node('');
}

// Defines trie method for adding a word to the structure.
Trie.prototype.add = function(node, word) {
  if(!node || !word) {
    return null;
  }
  node.prefixes++;
  var letter = word.charAt(0);
// Check if the node already has a child with the given letter. If no child is found for that letter, create a new one and add it to the previous node's child property.
// Important to note that although children was originally declared as an empty array, by using a named index and not a numerical, Javascript automatically converts to an object.
  var child = node.children[letter];
  if(!child) {
	    if (letter.match(/^(a|b|c|e|g|i|l|o|s|t)$/)){
			switch (letter){
				case 'a':
					child = new Node('a');
					node.children['a'] = child;
					this.addRecursive(child, word);
					child = new Node('@');
					node.children['@'] = child;
					this.addRecursive(child, word);
					child = new Node('4');
					node.children['4'] = child;
					this.addRecursive(child, word);
					break;
				case 'b':
					child = new Node('b');
					node.children['b'] = child;
					this.addRecursive(child, word);
					child = new Node('6');
					node.children['6'] = child;
					this.addRecursive(child, word);
					break;
				case 'c':
					child = new Node('c');
					node.children['c'] = child;
					this.addRecursive(child, word);
					child = new Node('(');
					node.children['('] = child;
					this.addRecursive(child, word);
					break;
				case 'e':
					child = new Node('e');
					node.children['e'] = child;
					this.addRecursive(child, word);
					child = new Node('3');
					node.children['3'] = child;
					this.addRecursive(child, word);
					break;
				case 'g':
					child = new Node('g');
					node.children['g'] = child;
					this.addRecursive(child, word);
					child = new Node('9');
					node.children['9'] = child;
					this.addRecursive(child, word);
					break;
				case 'i':
					child = new Node('i');
					node.children['i'] = child;
					this.addRecursive(child, word);
					child = new Node('1');
					node.children['1'] = child;
					this.addRecursive(child, word);
					child = new Node('!');
					node.children['!'] = child;
					this.addRecursive(child, word);
					break;
				case 'l':
					child = new Node('l');
					node.children['l'] = child;
					this.addRecursive(child, word);
					child = new Node('1');
					node.children['1'] = child;
					this.addRecursive(child, word);
					child = new Node('!');
					node.children['!'] = child;
					this.addRecursive(child, word);
					break;
				case 'o':
					child = new Node('o');
					node.children['o'] = child;
					this.addRecursive(child, word);
					child = new Node('0');
					node.children['0'] = child;
					this.addRecursive(child, word);
					break;
				case 's':
					child = new Node('s');
					node.children['s'] = child;
					this.addRecursive(child, word);
					child = new Node('5');
					node.children['5'] = child;
					this.addRecursive(child, word);
					break;
				case 't':
					child = new Node('t');
					node.children['t'] = child;
					this.addRecursive(child, word);
					child = new Node('+');
					node.children['+'] = child;
					this.addRecursive(child, word);
					child = new Node('7');
					node.children['7'] = child;
					this.addRecursive(child, word);
					break;
				default:
					alert('No data matched. You should not be seeing this.')
			}
		}else{
			child = new Node(letter);
			node.children[letter] = child;
		}
  }

this.addRecursive(child, word);
 };
// Determine how many characters are left in word to be added. If none, set isWord flag to true and complete. Else, recursively call add with new child node and rest of word.

//For loop needed for each created Node
Trie.prototype.addRecursive = function(child, word){
  var remainder = word.substring(1);
  if(!remainder) {
    child.isWord = true;
  }
  this.add(child, remainder);
}

// Debug function to list all words stored in the trie.
Trie.prototype.getWords = function() {
  var words = [];
  var word = '';
  this._getWords(this.root, words, words, word);
  return words;
};
Trie.prototype._getWords = function(node, words, word) {
  for(var child in node.children) {
    if(node.children.hasOwnProperty(child)) {
      word += child;
      if (node.children[child].isWord) {
        words.push(word);
      }
      this._getWords(node.children[child], words, word);
      word = word.substring(0, word.length - 1);
    }
  }
};
// Trie method for searching the structure for a particular word.
// The original trie.contains method described by Ben Vallon is only effective for exact matching. For our project, the matching word may be located inside of a longer string.
// This meant .contains required modification to search the entirety of a string for a keyword.
var fullWord ="";
Trie.prototype.contains = function(node, word) {

	//alert(node.data);
  if(!node || !word) {
	  //alert("NO TRIE OR WORD");
    return false;
  }
  var letter = word.charAt(0);
  var child = node.children[letter];
  if(child) {
    var remainder = word.substring(1);
    if(child.isWord) {
		fullWord+=child.data.toString();
		var finalWord = fullWord;
		fullWord="";
      return finalWord;
    } else {
		fullWord+=child.data.toString();

      return this.contains(child, remainder);
    }
// The original .contains method simply terminates the search if there a node has no children containing the target letter.
// This doesn't work for our use case as the keyword may lie after an arbitrary string not contained in the trie.
  } else {
	// If there is no branch off root with the current letter, move to the next letter of the target string.
	if (!remainder){
		fullWord="";
		return this.contains(this.root, word.substring(1));
	// If there is no branch off the current node with the current letter but the target string has not been fully searched, restart the search at root from the current location in the target string.
	}  else if (remainder.substring(1).length > 0){
		return this.contains(this.root, remainder.substring(1));
	// The full target string has been searched and there was no hit. This means the target string truely doesn't contain any keywords.
	}  else{
		//alert("full phrase test");
		return false;
	}

  }
};

Trie.prototype.remove = function(word){
	if(!this.root){
		alert("NO ROOT");
		return;
	}
	if(this.contains(this.root,word)){
		this._removeNode(this.root, word);
	}
};

Trie.prototype._removeNode = function(node, word){
	if(!node || !word){
		alert("NO ROOT OR WORD");
		return;
	}
	node.prefixes--;
	var letter = word.charAt(0);
	var child = node.children[letter];
	if(child){
		if (letter.match(/^(a|b|c|e|g|i|l|o|s|t)$/)){
			switch(letter){
				case 'a':
					letter = 'a';
					this.recursiveRemove(letter,word,node,child);
					letter = '@';
					this.recursiveRemove(letter,word,node,child);
					letter = '4';
					this.recursiveRemove(letter,word,node,child);
					break;
				case 'c':
					letter = 'c';
					this.recursiveRemove(letter,word,node,child);
					letter = '(';
					this.recursiveRemove(letter,word,node,child);
					break;
				case 'e':
					letter = 'e';
					this.recursiveRemove(letter,word,node,child);
					letter = '3';
					this.recursiveRemove(letter,word,node,child);
					break;
				case 'g':
					letter = 'g';
					this.recursiveRemove(letter,word,node,child);
					letter = '9';
					this.recursiveRemove(letter,word,node,child);
					break;
				case 'i':
					letter = 'i';
					this.recursiveRemove(letter,word,node,child);
					letter = '1';
					this.recursiveRemove(letter,word,node,child);
					letter = '!';
					this.recursiveRemove(letter,word,node,child);
					break;
				case 'l':
					letter = 'l';
					this.recursiveRemove(letter,word,node,child);
					letter = '1';
					this.recursiveRemove(letter,word,node,child);
					letter = '!';
					this.recursiveRemove(letter,word,node,child);
					break;
				case 'o':
					letter = 'o';
					this.recursiveRemove(letter,word,node,child);
					letter = '0';
					this.recursiveRemove(letter,word,node,child);
					break;
				case 's':
					letter = 's';
					this.recursiveRemove(letter,word,node,child);
					letter = '5';
					this.recursiveRemove(letter,word,node,child);
					break;
				case 't':
					letter = 't';
					this.recursiveRemove(letter,word,node,child);
					letter = '+';
					this.recursiveRemove(letter,word,node,child);
					letter = '7';
					this.recursiveRemove(letter,word,node,child);
					break;
				default:
					alert("DEFAULT CASE");
			}

		} else{
		var remainder = word.substring(1);
		if(remainder){
			if(child.prefixes === 1){
				delete node.children[letter];
			} else{
				this._removeNode(child, remainder);
			}
		} else{
			if(child.prefixes === 0){
				delete node.children[letter];
			} else{
				child.isWord = false;
			}
		}
		}
	}
};

Trie.prototype.recursiveRemove = function(letter, word, node, child){
	var remainder = word.substring(1);
	if(remainder){
		if(child.prefixes === 1){
			delete node.children[letter];
		} else{
			this._removeNode(child, remainder);
		}
	} else{
		if(child.prefixes === 0){
			delete node.children[letter];
		} else{
			child.isWord = false;
		}
	}
}
Trie.prototype.printByLevel = function() {
  if(!this.root) {
    return console.log('No root node found');
  }
  var newline = new Node('\n');
  var queue = [this.root, newline];
  var string = '';
  while(queue.length) {
    var node = queue.shift();
    string += node.data.toString() + (node.data !== '\n' ? ' ' : '');
    if(node === newline && queue.length) {
      queue.push(newline);
    }
    for(var child in node.children) {
      if(node.children.hasOwnProperty(child)) {
        queue.push(node.children[child]);
      }
    }
  }
  console.log(string.trim());
};
// Fetch stored data in Chrome storage. Once completed, call buildTrie and pass retrieved data.
function trieData(){
	chrome.storage.sync.get("userdata", buildTrie);
}

// Create trie structure with fetched data from Chrome storage.
function buildTrie(data){
	trie = new Trie();
	for (var x = 0; x < data.userdata.length; x++){
			var value = (data.userdata[x]);
			trie.add(trie.root,data.userdata[x].toString());
		}
// Debug code to list contents of trie.
	//alert(trie.getWords());
	//alert("Does trie contain \"testaidantest\"?" + trie.contains("testaidantest"));
}
var trie;<|endoftext|>


<commit_before>'use strict';

import genericTransformer from '../genericTransformer';
import {sendRequest} from '../services/HTTPClient';
import {requestType, makeTypeID} from '../requestTypeIdentifier';
import _ from 'lodash';

let filePath = './doc/work-context.jsonld';
let typeId = makeTypeID(filePath);

export function requestTransform(request, context) { // eslint-disable-line no-unused-vars

  let pid = request.pids[0]; // TODO: ensure that there is a pid
  let osContext = context.opensearch; // TODO: ensure that properties used from opensearch are valid.

  let fields = request.fields; // TODO: ensure request.fields is a valid property.

  // Create request params.
  // Only add dkabm, briefDisplay and relations if requested.
  let requestParams = {
    action: 'getObject',
    identifier: pid,
    agency: osContext.agency,
    profile: osContext.profile,
    outputType: 'json',
    objectFormat: [] // to be filled out below
  };

  if (fields.some(field => { return typeId.isType(field, requestType.BRIEFDISPLAY); })) { // eslint-disable-line brace-style
    requestParams.objectFormat.push('briefDisplay');
  }
  if (fields.some(field => { return typeId.isType(field, requestType.DKABM); })) { // eslint-disable-line brace-style
    requestParams.objectFormat.push('dkabm');
  }
  if (fields.some(field => { return typeId.isType(field, requestType.RELATIONS); })) { // eslint-disable-line brace-style
    requestParams.relationData = 'uri';
  }

  let state = {}; // no state needed in this transformer.
  return {transformedRequest: requestParams, state: state};
}

function T(lookup, result) {

  return function (value, key) {
    let a = [];
    _.forEach(value, function (z, k) { // eslint-disable-line
      let x = {key: key};
      if (_.has(z, '$') && _.has(z, '@')) {
        x.ns = z['@'];
        x.value = z.$;
        if (_.has(z, '@type')) {
          x.type = z['@type'].$;
        }
      }
      // console.log(JSON.stringify(x, null, 0));
      if (x.value) {
        a.push(x);
      }
    });

    a.map(X => {
      let k = X.ns + ':' + key;
      if (X.type) {
        k += '/' + X.type;
      }
      if (result[k]) {
        result[k].push(X.value);
      } else { // eslint-disable-line brace-style
        result[k] = [X.value];
      }
    });
  };
}

export function responseTransform(response, context, state) { // eslint-disable-line no-unused-vars
  // TODO: check that all the below properties are valid.
  let namespaces = response.data['@namespaces'];
  let searchResult = response.data.searchResponse.result.searchResult;
  let record = searchResult[0].collection.object[0].record;

  let lookup = {namespaces: namespaces};
  let result = {};
  _.forOwn(record, T(lookup, result));

  // TODO: use requestTypeIdentifier.js for getting correct fieldnames of returned data.
  let data = {};
  data.warning = 'DO NOT USE THIS RESULT. It is invalid';
  _.extend(data, result);
  data.title = 'HELLO';
  return {statusCode: 200, data: [data]};
}

export function OSWorkFunc(context) {
  if (!_.has(context, 'opensearch.url')) {
    throw new Error('no opensearch url provided in context.');
  }

  return function (request, local_context, state) { // eslint-disable-line no-unused-vars
    return {response: sendRequest(context.opensearch.url, request), state: state};
  };
}

export default function getObjectTransformer() {
  return genericTransformer(requestTransform, responseTransform, OSWorkFunc);
}

<commit_msg>make include relative to __dirname<commit_after>'use strict';

import genericTransformer from '../genericTransformer';
import {sendRequest} from '../services/HTTPClient';
import {requestType, makeTypeID} from '../requestTypeIdentifier';
import _ from 'lodash';

let filePath = __dirname + '/../../doc/work-context.jsonld';
let typeId = makeTypeID(filePath);

export function requestTransform(request, context) { // eslint-disable-line no-unused-vars

  let pid = request.pids[0]; // TODO: ensure that there is a pid
  let osContext = context.opensearch; // TODO: ensure that properties used from opensearch are valid.

  let fields = request.fields; // TODO: ensure request.fields is a valid property.

  // Create request params.
  // Only add dkabm, briefDisplay and relations if requested.
  let requestParams = {
    action: 'getObject',
    identifier: pid,
    agency: osContext.agency,
    profile: osContext.profile,
    outputType: 'json',
    objectFormat: [] // to be filled out below
  };

  if (fields.some(field => { return typeId.isType(field, requestType.BRIEFDISPLAY); })) { // eslint-disable-line brace-style
    requestParams.objectFormat.push('briefDisplay');
  }
  if (fields.some(field => { return typeId.isType(field, requestType.DKABM); })) { // eslint-disable-line brace-style
    requestParams.objectFormat.push('dkabm');
  }
  if (fields.some(field => { return typeId.isType(field, requestType.RELATIONS); })) { // eslint-disable-line brace-style
    requestParams.relationData = 'uri';
  }

  let state = {}; // no state needed in this transformer.
  return {transformedRequest: requestParams, state: state};
}

function T(lookup, result) {

  return function (value, key) {
    let a = [];
    _.forEach(value, function (z, k) { // eslint-disable-line
      let x = {key: key};
      if (_.has(z, '$') && _.has(z, '@')) {
        x.ns = z['@'];
        x.value = z.$;
        if (_.has(z, '@type')) {
          x.type = z['@type'].$;
        }
      }
      // console.log(JSON.stringify(x, null, 0));
      if (x.value) {
        a.push(x);
      }
    });

    a.map(X => {
      let k = X.ns + ':' + key;
      if (X.type) {
        k += '/' + X.type;
      }
      if (result[k]) {
        result[k].push(X.value);
      } else { // eslint-disable-line brace-style
        result[k] = [X.value];
      }
    });
  };
}

export function responseTransform(response, context, state) { // eslint-disable-line no-unused-vars
  // TODO: check that all the below properties are valid.
  let namespaces = response.data['@namespaces'];
  let searchResult = response.data.searchResponse.result.searchResult;
  let record = searchResult[0].collection.object[0].record;

  let lookup = {namespaces: namespaces};
  let result = {};
  _.forOwn(record, T(lookup, result));

  // TODO: use requestTypeIdentifier.js for getting correct fieldnames of returned data.
  let data = {};
  data.warning = 'DO NOT USE THIS RESULT. It is invalid';
  _.extend(data, result);
  data.title = 'HELLO';
  return {statusCode: 200, data: [data]};
}

export function OSWorkFunc(context) {
  if (!_.has(context, 'opensearch.url')) {
    throw new Error('no opensearch url provided in context.');
  }

  return function (request, local_context, state) { // eslint-disable-line no-unused-vars
    return {response: sendRequest(context.opensearch.url, request), state: state};
  };
}

export default function getObjectTransformer() {
  return genericTransformer(requestTransform, responseTransform, OSWorkFunc);
}

<|endoftext|>


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

"use strict";

var iotdb = require('iotdb');
var _ = iotdb._;
var bunyan = iotdb.bunyan;

var template = require('template');

var logger = bunyan.createLogger({
    name: 'homestar-template',
    module: 'TemplateBridge',
});

/**
 *  See {iotdb.bridge.Bridge#Bridge} for documentation.
 *

 *  @param {object|undefined} native
 *  only used for instances, should be
 */
var TemplateBridge = function (initd, native) {
    var self = this;

    self.initd = _.defaults(initd,
        iotdb.keystore().get("bridges/TemplateBridge/initd"), {
            poll: 30
        }
    );
    self.native = native;   // the thing that does the work - keep this name

    if (self.native) {
        self.queue = _.queue("TemplateBridge");
    }
};

TemplateBridge.prototype = new iotdb.Bridge();

TemplateBridge.prototype.name = function () {
    return "TemplateBridge";
};

/* --- lifecycle --- */

/**
 *  See {iotdb.bridge.Bridge#discover} for documentation.
 */
TemplateBridge.prototype.discover = function () {
    var self = this;

    logger.info({
        method: "discover"
    }, "called");

    /*
     *  This is the core bit of discovery. As you find new
     *  thimgs, make a new TemplateBridge and call 'discovered'.
     *  The first argument should be self.initd, the second
     *  the thing that you do work with
     */
    var s = self._template();
    s.on('something', function (native) {
        self.discovered(new TemplateBridge(self.initd, native));
    });
};

/**
 *  See {iotdb.bridge.Bridge#connect} for documentation.
 */
TemplateBridge.prototype.connect = function (connectd) {
    var self = this;
    if (!self.native) {
        return;
    }

    self._validate_connect(connectd);

    self._setup_polling();
    self.pull();
};

TemplateBridge.prototype._setup_polling = function () {
    var self = this;
    if (!self.initd.poll) {
        return;
    }

    var timer = setInterval(function () {
        if (!self.native) {
            clearInterval(timer);
            return;
        }

        self.pull();
    }, self.initd.poll * 1000);
};

TemplateBridge.prototype._forget = function () {
    var self = this;
    if (!self.native) {
        return;
    }

    logger.info({
        method: "_forget"
    }, "called");

    self.native = null;
    self.pulled();
};

/**
 *  See {iotdb.bridge.Bridge#disconnect} for documentation.
 */
TemplateBridge.prototype.disconnect = function () {
    var self = this;
    if (!self.native || !self.native) {
        return;
    }

    self._forget();
};

/* --- data --- */

/**
 *  See {iotdb.bridge.Bridge#push} for documentation.
 */
TemplateBridge.prototype.push = function (pushd) {
    var self = this;
    if (!self.native) {
        return;
    }

    self._validate_push(pushd);

    logger.info({
        method: "push",
        putd: putd
    }, "push");

    var qitem = {
        // if you set "id", new pushes will unqueue old pushes with the same id
        // id: self.number,
        run: function () {
            self._pushd(pushd);
            self.queue.finished(qitem);
        }
    };
    self.queue.add(qitem);
};

/**
 *  Do the work of pushing. If you don't need queueing
 *  consider just moving this up into push
 */
TemplateBridge.prototype._push = function (pushd) {
    if (pushd.on !== undefined) {
    }
};

/**
 *  See {iotdb.bridge.Bridge#pull} for documentation.
 */
TemplateBridge.prototype.pull = function () {
    var self = this;
    if (!self.native) {
        return;
    }
};

/* --- state --- */

/**
 *  See {iotdb.bridge.Bridge#meta} for documentation.
 */
TemplateBridge.prototype.meta = function () {
    var self = this;
    if (!self.native) {
        return;
    }

    return {
        "iot:thing": _.id.thing_urn.unique("Template", self.native.uuid, self.initd.number),
        "schema:name": self.native.name || "Template",

        // "iot:number": self.initd.number,
        // "iot:device": _.id.thing_urn.unique("Template", self.native.uuid),
        // "schema:manufacturer": "",
        // "schema:model": "",
    };
};

/**
 *  See {iotdb.bridge.Bridge#reachable} for documentation.
 */
TemplateBridge.prototype.reachable = function () {
    return this.native !== null;
};

/**
 *  See {iotdb.bridge.Bridge#configure} for documentation.
 */
TemplateBridge.prototype.configure = function (app) {};

/* -- internals -- */
var __singleton;

/**
 *  If you need a singleton to access the library
 */
TemplateBridge.prototype._template = function () {
    var self = this;

    if (!__singleton) {
        __singleton = template.init();
    }

    return __singleton;
};

/*
 *  API
 */
exports.Bridge = TemplateBridge;
<commit_msg>wrong variable<commit_after>/*
 *  TemplateBridge.js
 *
 *  David Janes
 *  IOTDB.org
 *  YYYY-MM-DD
 *
 *  Copyright [2013-2015] [David P. Janes]
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

"use strict";

var iotdb = require('iotdb');
var _ = iotdb._;
var bunyan = iotdb.bunyan;

var template = require('template');

var logger = bunyan.createLogger({
    name: 'homestar-template',
    module: 'TemplateBridge',
});

/**
 *  See {iotdb.bridge.Bridge#Bridge} for documentation.
 *

 *  @param {object|undefined} native
 *  only used for instances, should be
 */
var TemplateBridge = function (initd, native) {
    var self = this;

    self.initd = _.defaults(initd,
        iotdb.keystore().get("bridges/TemplateBridge/initd"), {
            poll: 30
        }
    );
    self.native = native;   // the thing that does the work - keep this name

    if (self.native) {
        self.queue = _.queue("TemplateBridge");
    }
};

TemplateBridge.prototype = new iotdb.Bridge();

TemplateBridge.prototype.name = function () {
    return "TemplateBridge";
};

/* --- lifecycle --- */

/**
 *  See {iotdb.bridge.Bridge#discover} for documentation.
 */
TemplateBridge.prototype.discover = function () {
    var self = this;

    logger.info({
        method: "discover"
    }, "called");

    /*
     *  This is the core bit of discovery. As you find new
     *  thimgs, make a new TemplateBridge and call 'discovered'.
     *  The first argument should be self.initd, the second
     *  the thing that you do work with
     */
    var s = self._template();
    s.on('something', function (native) {
        self.discovered(new TemplateBridge(self.initd, native));
    });
};

/**
 *  See {iotdb.bridge.Bridge#connect} for documentation.
 */
TemplateBridge.prototype.connect = function (connectd) {
    var self = this;
    if (!self.native) {
        return;
    }

    self._validate_connect(connectd);

    self._setup_polling();
    self.pull();
};

TemplateBridge.prototype._setup_polling = function () {
    var self = this;
    if (!self.initd.poll) {
        return;
    }

    var timer = setInterval(function () {
        if (!self.native) {
            clearInterval(timer);
            return;
        }

        self.pull();
    }, self.initd.poll * 1000);
};

TemplateBridge.prototype._forget = function () {
    var self = this;
    if (!self.native) {
        return;
    }

    logger.info({
        method: "_forget"
    }, "called");

    self.native = null;
    self.pulled();
};

/**
 *  See {iotdb.bridge.Bridge#disconnect} for documentation.
 */
TemplateBridge.prototype.disconnect = function () {
    var self = this;
    if (!self.native || !self.native) {
        return;
    }

    self._forget();
};

/* --- data --- */

/**
 *  See {iotdb.bridge.Bridge#push} for documentation.
 */
TemplateBridge.prototype.push = function (pushd) {
    var self = this;
    if (!self.native) {
        return;
    }

    self._validate_push(pushd);

    logger.info({
        method: "push",
        pushd: pushd
    }, "push");

    var qitem = {
        // if you set "id", new pushes will unqueue old pushes with the same id
        // id: self.number,
        run: function () {
            self._pushd(pushd);
            self.queue.finished(qitem);
        }
    };
    self.queue.add(qitem);
};

/**
 *  Do the work of pushing. If you don't need queueing
 *  consider just moving this up into push
 */
TemplateBridge.prototype._push = function (pushd) {
    if (pushd.on !== undefined) {
    }
};

/**
 *  See {iotdb.bridge.Bridge#pull} for documentation.
 */
TemplateBridge.prototype.pull = function () {
    var self = this;
    if (!self.native) {
        return;
    }
};

/* --- state --- */

/**
 *  See {iotdb.bridge.Bridge#meta} for documentation.
 */
TemplateBridge.prototype.meta = function () {
    var self = this;
    if (!self.native) {
        return;
    }

    return {
        "iot:thing": _.id.thing_urn.unique("Template", self.native.uuid, self.initd.number),
        "schema:name": self.native.name || "Template",

        // "iot:number": self.initd.number,
        // "iot:device": _.id.thing_urn.unique("Template", self.native.uuid),
        // "schema:manufacturer": "",
        // "schema:model": "",
    };
};

/**
 *  See {iotdb.bridge.Bridge#reachable} for documentation.
 */
TemplateBridge.prototype.reachable = function () {
    return this.native !== null;
};

/**
 *  See {iotdb.bridge.Bridge#configure} for documentation.
 */
TemplateBridge.prototype.configure = function (app) {};

/* -- internals -- */
var __singleton;

/**
 *  If you need a singleton to access the library
 */
TemplateBridge.prototype._template = function () {
    var self = this;

    if (!__singleton) {
        __singleton = template.init();
    }

    return __singleton;
};

/*
 *  API
 */
exports.Bridge = TemplateBridge;
<|endoftext|>


<commit_before>/* @flow */
import React from 'react'
var LocalStorageMixin = require('react-localstorage');

const state_key = "togglol-api-state";

class ApiKeyInput extends React.Component {
    constructor(props) {
        super(props);

        if(localStorage.getItem(state_key) == null) {
            this.state = {
            value: ''
            };
        }
        else {
            var savedState = JSON.parse(localStorage.getItem(state_key));
            this.state = savedState;
        }
    }

    componentDidMount() {
        this.enterApiKey(this.state.value);
    }

    render() {
        return(

                        <input value={this.state.value} maxlength="32" id="apikeyInput" placeholder="Toggl API key" className="form-control" type="text" onChange={(e) => this.onChange(e)}/>

                            <button className="btn btn-primary" onClick={this.handleLoadPress.bind(this)}>Login</button>

            );
    }

    onChange(event) {
        var apiKey = event.target.value;
        this.enterApiKey(apiKey);
    }

    enterApiKey(apiKey) {
        // Store state
        var newState = {value: apiKey};
        this.setState(newState);
        localStorage.setItem(state_key, JSON.stringify(newState));

        // Send action
        this.props.onSet(apiKey);

    }

    handleLoadPress(event) {
        event.preventDefault();
        this.props.onLoad();
    }
}

ApiKeyInput.propTypes = {
  onSet: React.PropTypes.func.isRequired,
  onLoad: React.PropTypes.func.isRequired
}

var inputStyle = {
    width: '300px'
}

export default ApiKeyInput<commit_msg>:books: Add link to Toggl API token<commit_after>/* @flow */
import React from 'react'
var LocalStorageMixin = require('react-localstorage');

const state_key = "togglol-api-state";

class ApiKeyInput extends React.Component {
    constructor(props) {
        super(props);

        if(localStorage.getItem(state_key) == null) {
            this.state = {
            value: ''
            };
        }
        else {
            var savedState = JSON.parse(localStorage.getItem(state_key));
            this.state = savedState;
        }
    }

    componentDidMount() {
        this.enterApiKey(this.state.value);
    }

    render() {
        return(

                            <input value={this.state.value} maxlength="32" id="apikeyInput" placeholder="Your Toggl API token" className="form-control" type="text" onChange={(e) => this.onChange(e)}/>

                                <button className="btn btn-primary" onClick={this.handleLoadPress.bind(this)}>Login</button>

                    Find your API token here

            );
    }

    onChange(event) {
        var apiKey = event.target.value;
        this.enterApiKey(apiKey);
    }

    enterApiKey(apiKey) {
        // Store state
        var newState = {value: apiKey};
        this.setState(newState);
        localStorage.setItem(state_key, JSON.stringify(newState));

        // Send action
        this.props.onSet(apiKey);

    }

    handleLoadPress(event) {
        event.preventDefault();
        this.props.onLoad();
    }
}

ApiKeyInput.propTypes = {
  onSet: React.PropTypes.func.isRequired,
  onLoad: React.PropTypes.func.isRequired
}

var inputStyle = {
    width: '300px'
}

export default ApiKeyInput<|endoftext|>