<commit_before>module.exports = {

//---------------------------------------------------------------------
// Action Name
//
// This is the name of the action displayed in the editor.
//---------------------------------------------------------------------

name: "Convert Timestamp to Date",

//---------------------------------------------------------------------
// Action Section
//
// This is the section the action will fall into.
//---------------------------------------------------------------------

section: "Other Stuff",

//---------------------------------------------------------------------
// Action Subtitle
//
// This function generates the subtitle displayed next to the name.
//---------------------------------------------------------------------

subtitle: function(data) {
return `Convert ${data.time}`;
},

//---------------------------------------------------------------------
	 // DBM Mods Manager Variables (Optional but nice to have!)
	 //
	 // These are variables that DBM Mods Manager uses to show information
	 // about the mods for people to see in the list.
	 //---------------------------------------------------------------------

 // Who made the mod (If not set, defaults to "DBM Mods")
 author: "iAmaury", //Idea by Tresmos

 // The version of the mod (Defaults to 1.0.0)
 version: "1.8.7", //Added in 1.8.6

 // A short description to show on the mod line for this mod (Must be on a single line)
 short_description: "Convert Timestamp to date.",

 // If it depends on any other mods by name, ex: WrexMODS if the mod uses something from WrexMods

 //---------------------------------------------------------------------

//---------------------------------------------------------------------
// Action Storage Function
//
// Stores the relevant variable info for the editor.
//---------------------------------------------------------------------

variableStorage: function(data, varType) {
		const type = parseInt(data.storage);
		if(type !== varType) return;
		return ([data.varName, 'Date']);
	},

//---------------------------------------------------------------------
// Action Fields
//
// These are the fields for the action. These fields are customized
// by creating elements with corresponding IDs in the HTML. These
// are also the names of the fields stored in the action's JSON data.
//---------------------------------------------------------------------

fields: ["time", "storage", "varName"],

//---------------------------------------------------------------------
// Command HTML
//
// This function returns a string containing the HTML used for
// editting actions.
//
// The "isEvent" parameter will be true if this action is being used
// for an event. Due to their nature, events lack certain information,
// so edit the HTML to reflect this.
//
// The "data" parameter stores constants for select elements to use.
// Each is an array: index 0 for commands, index 1 for events.
// The names are: sendTargets, members, roles, channels,
//                messages, servers, variables
//---------------------------------------------------------------------

html: function(isEvent, data) {
	return `

Mod Info:

		Made by iAmaury !

Suggested by Jakob !

Note:

		You can convert Unix Timestamp and YouTube Timestamp with this mod (both were tested).

		Timestamp to Convert:
		<input id="time" class="round" type="text" placeholder="1522672056">

		Store Result In:

		<select id="storage" class="round" onchange="glob.variableChange(this, 'varNameContainer')">
		${data.variables[0]}
		</select>

		Variable Name:

		<input id="varName" class="round" type="text">

Available formats for timestamp:

Do not include toDate, '' and ()

`;
},

//---------------------------------------------------------------------
// Action Editor Init Code
//
// When the HTML is first applied to the action editor, this code
// is also run. This helps add modifications or setup reactionary
// functions for the DOM elements.
//---------------------------------------------------------------------

init: function() {
	const {glob, document} = this;

	glob.variableChange(document.getElementById('storage'), 'varNameContainer');
},

//---------------------------------------------------------------------
// Action Bot Function
//
// This is the function for the action within the Bot's Action class.
// Keep in mind event calls won't have access to the "msg" parameter,
// so be sure to provide checks for variable existance.
//---------------------------------------------------------------------

action: function(cache) {

	const data = cache.actions[cache.index];
	var   _this = this; // this is needed sometimes.
	const WrexMODS = _this.getWrexMods(); // as always.
	const toDate = WrexMODS.require('normalize-date');
	const time = this.evalMessage(data.time, cache);

    // Main code.
	let result;
	if (/^\d+(?:\.\d*)?$/.exec(time)) {
  		result = toDate((+time).toFixed(3));
	}
	else {
		result = toDate(time);
	}
	if (result.toString() === "Invalid Date") result = undefined;

    // Storage.
	if(result !== undefined) {
		const storage = parseInt(data.storage);
		const varName = this.evalMessage(data.varName, cache);
		this.storeValue(result, storage, varName, cache);
	}
    this.callNextAction(cache);
},

//---------------------------------------------------------------------
// Action Bot Mod
//
// Upon initialization of the bot, this code is run. Using the bot's
// DBM namespace, one can add/modify existing functions if necessary.
// In order to reduce conflictions between mods, be sure to alias
// functions you wish to overwrite.
//---------------------------------------------------------------------

mod: function(DBM) {
}

}; // End of module
<commit_msg>Edited the placeholder - don't download<commit_after>module.exports = {

//---------------------------------------------------------------------
// Action Name
//
// This is the name of the action displayed in the editor.
//---------------------------------------------------------------------

name: "Convert Timestamp to Date",

//---------------------------------------------------------------------
// Action Section
//
// This is the section the action will fall into.
//---------------------------------------------------------------------

section: "Other Stuff",

//---------------------------------------------------------------------
// Action Subtitle
//
// This function generates the subtitle displayed next to the name.
//---------------------------------------------------------------------

subtitle: function(data) {
return `Convert ${data.time}`;
},

//---------------------------------------------------------------------
	 // DBM Mods Manager Variables (Optional but nice to have!)
	 //
	 // These are variables that DBM Mods Manager uses to show information
	 // about the mods for people to see in the list.
	 //---------------------------------------------------------------------

 // Who made the mod (If not set, defaults to "DBM Mods")
 author: "iAmaury", //Idea by Tresmos

 // The version of the mod (Defaults to 1.0.0)
 version: "1.8.7", //Added in 1.8.6

 // A short description to show on the mod line for this mod (Must be on a single line)
 short_description: "Convert Timestamp to date.",

 // If it depends on any other mods by name, ex: WrexMODS if the mod uses something from WrexMods

 //---------------------------------------------------------------------

//---------------------------------------------------------------------
// Action Storage Function
//
// Stores the relevant variable info for the editor.
//---------------------------------------------------------------------

variableStorage: function(data, varType) {
		const type = parseInt(data.storage);
		if(type !== varType) return;
		return ([data.varName, 'Date']);
	},

//---------------------------------------------------------------------
// Action Fields
//
// These are the fields for the action. These fields are customized
// by creating elements with corresponding IDs in the HTML. These
// are also the names of the fields stored in the action's JSON data.
//---------------------------------------------------------------------

fields: ["time", "storage", "varName"],

//---------------------------------------------------------------------
// Command HTML
//
// This function returns a string containing the HTML used for
// editting actions.
//
// The "isEvent" parameter will be true if this action is being used
// for an event. Due to their nature, events lack certain information,
// so edit the HTML to reflect this.
//
// The "data" parameter stores constants for select elements to use.
// Each is an array: index 0 for commands, index 1 for events.
// The names are: sendTargets, members, roles, channels,
//                messages, servers, variables
//---------------------------------------------------------------------

html: function(isEvent, data) {
	return `

Mod Info:

		Made by iAmaury !

Note:

		You can convert Unix Timestamp and YouTube Timestamp with this mod (both were tested).

		Timestamp to Convert:
		<input id="time" class="round" type="text" placeholder="e.g. 1522672056">

		Store Result In:

		<select id="storage" class="round" onchange="glob.variableChange(this, 'varNameContainer')">
		${data.variables[0]}
		</select>

		Variable Name:

		<input id="varName" class="round" type="text">

Available formats for timestamp:

Do not include toDate, '' and ()

`;
},

//---------------------------------------------------------------------
// Action Editor Init Code
//
// When the HTML is first applied to the action editor, this code
// is also run. This helps add modifications or setup reactionary
// functions for the DOM elements.
//---------------------------------------------------------------------

init: function() {
	const {glob, document} = this;

	glob.variableChange(document.getElementById('storage'), 'varNameContainer');
},

//---------------------------------------------------------------------
// Action Bot Function
//
// This is the function for the action within the Bot's Action class.
// Keep in mind event calls won't have access to the "msg" parameter,
// so be sure to provide checks for variable existance.
//---------------------------------------------------------------------

action: function(cache) {

	const data = cache.actions[cache.index];
	var   _this = this; // this is needed sometimes.
	const WrexMODS = _this.getWrexMods(); // as always.
	const toDate = WrexMODS.require('normalize-date');
	const time = this.evalMessage(data.time, cache);

    // Main code.
	let result;
	if (/^\d+(?:\.\d*)?$/.exec(time)) {
  		result = toDate((+time).toFixed(3));
	}
	else {
		result = toDate(time);
	}
	if (result.toString() === "Invalid Date") result = undefined;

    // Storage.
	if(result !== undefined) {
		const storage = parseInt(data.storage);
		const varName = this.evalMessage(data.varName, cache);
		this.storeValue(result, storage, varName, cache);
	}
    this.callNextAction(cache);
},

//---------------------------------------------------------------------
// Action Bot Mod
//
// Upon initialization of the bot, this code is run. Using the bot's
// DBM namespace, one can add/modify existing functions if necessary.
// In order to reduce conflictions between mods, be sure to alias
// functions you wish to overwrite.
//---------------------------------------------------------------------

mod: function(DBM) {
}

}; // End of module
<|endoftext|>


<commit_before>/* eslint-disable object-shorthand */

// Get various parts of the WebExtension framework that we need.
var { ExtensionCommon } = ChromeUtils.import("resource://gre/modules/ExtensionCommon.jsm");

// You probably already know what this does.
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");

// This is the important part. It implements the functions and events defined in schema.json.
// The variable must have the same name you've been using so far, "myapi" in this case.
var compose_ext = class extends ExtensionCommon.ExtensionAPI {
  getAPI(context) {
    let { extension } = context;
    let { tabManager, windowManager } = extension;
    async function getTabWindow(tabId){
      return (await tabManager.get(tabId)).nativeTab;
    }
    return {
      // Again, this key must have the same name.
      compose_ext: {

        getCurrentLanguage: async function(tabId) {
          return (await getTabWindow(tabId)).document.documentElement.getAttribute("lang");
        },

        canSpellCheck: async function(tabId) {
          // todo: use tabId
          var window = await getTabWindow(tabId);
          return window.gSpellChecker && window.gSpellChecker.canSpellCheck && window.gSpellChecker.enabled;
        },

        setSpellCheckerLanguage: async function(tabId, lang) {
          var window = await getTabWindow(tabId);
          var fake_event = {
            target: {
              value: lang
            },
            stopPropagation: function(){}
          };
          return window.ChangeLanguage(fake_event);
        },

        showNotification: async function(tabId, string, options){
          options = options || {};
          var window = await getTabWindow(tabId);
          var notification_value = "show-message";
          //FIXME: DRY this code with changeLabel
          let nb = window.gNotification.notificationbox;
          var n = nb.getNotificationWithValue(notification_value);
          if(n) {
            n.label = string;
          } else {
            var buttons = options.buttons || [];
            var priority = nb.PRIORITY_INFO_HIGH;
            n = nb.appendNotification(string, notification_value, options.logo_url, priority, buttons);
          }
          // setup timeout
          if (options.notification_time) {
            if(this.label_timeout){
              window.clearTimeout(this.label_timeout);
            }
            this.label_timeout = window.setTimeout( function(){
              nb.removeNotification( n );
            }, options.notification_time);
          }
        },

        // An event. Most of this is boilerplate you don't need to worry about, just copy it.
        onLanguageChange: new ExtensionCommon.EventManager({
          context,
          name: "compose_ext.onLanguageChange",
          // In this function we add listeners for any events we want to listen to, and return a
          // function that removes those listeners. To have the event fire in your extension,
          // call fire.async.
          register(fire) {
            function callback(event_name, event, language) {
              let win = windowManager.wrapWindow(event.target.ownerGlobal);
              var tab = tabManager.convert(win.activeTab.nativeTab);
              return fire.async(tab.id, language);
            }

            windowListener.add(callback);
            return function() {
              windowListener.remove(callback);
            };
          },
        }).api(),

        onRecipientsChange: new ExtensionCommon.EventManager({
          context,
          name: "compose_ext.onRecipientsChange",
          // In this function we add listeners for any events we want to listen to, and return a
          // function that removes those listeners. To have the event fire in your extension,
          // call fire.async.
          register(fire) {
            function callback(event_name, event) {
              let win = windowManager.wrapWindow(event.target.ownerGlobal);
              var tab = tabManager.convert(win.activeTab.nativeTab);
              return fire.async(tab.id);
            }

            recipientsChangeWindowListener.add(callback);
            return function() {
              recipientsChangeWindowListener.remove(callback);
            };
          },
        }).api(),

      },
    };
  }
};

// A helpful class for listening to windows opening and closing.
// (This file had a lowercase E in Thunderbird 65 and earlier.)
var { ExtensionSupport } = ChromeUtils.import("resource:///modules/ExtensionSupport.jsm");

// This object is just what we're using to listen for toolbar clicks. The implementation isn't
// what this example is about, but you might be interested as it's a common pattern. We count the
// number of callbacks waiting for events so that we're only listening if we need to be.
var windowListener = new class extends ExtensionCommon.EventEmitter {
  constructor() {
    super();
    this.callbackCount = 0;
  }

  handleEvent(event) {
    var lang = event.target.getAttribute('lang');
    windowListener.emit("language-changed", event, lang);
  }

  add(callback) {
    this.on("language-changed", callback);
    this.callbackCount++;

    if (this.callbackCount == 1) {
      ExtensionSupport.registerWindowListener("compose_ext-windowListener", {
        //TODO: set composer url.
        chromeURLs: ["chrome://messenger/content/messengercompose/messengercompose.xhtml"],
        onLoadWindow: function(window) {
          windowListener.subscribeLanguageChangeEvents(window);
        },
      });
    }
  }

  remove(callback) {
    this.off("language-changed", callback);
    this.callbackCount--;

    if (this.callbackCount == 0) {
      ExtensionSupport.unregisterWindowListener("compose_ext-windowListener");
    }
  }

  subscribeLanguageChangeEvents(window) {
    //We don't capture "spellcheck-changed" event because it's only fired
    //when language is changed in the context menu (rigt click menu). Not when changed
    //from any other source.

    // The document lang attribute is updated always so its the best way.
    var langObserver = new window.MutationObserver(function(mutations) {
      mutations.forEach(function(mutation) {
        if (mutation.type == "attributes" && mutation.attributeName == "lang") {
          windowListener.handleEvent(mutation);
        }
      });
    });
    langObserver.observe(window.document.documentElement, { attributes: true });
  }
};

var recipientsChangeWindowListener = new class extends ExtensionCommon.EventEmitter {
  constructor() {
    super();
    this.callbackCount = 0;
  }

  handleEvent(event) {
    recipientsChangeWindowListener.emit("recipients-changed", event);
  }

  add(callback) {
    this.on("recipients-changed", callback);
    this.callbackCount++;

    if (this.callbackCount == 1) {
      ExtensionSupport.registerWindowListener("recipientsChangeWindowListener", {
        chromeURLs: ["chrome://messenger/content/messengercompose/messengercompose.xhtml"],
        onLoadWindow: function(window) {
          recipientsChangeWindowListener.detectRecipientsChange(window);
        },
      });
    }
  }

  remove(callback) {
    this.off("recipients-changed", callback);
    this.callbackCount--;

    if (this.callbackCount == 0) {
      ExtensionSupport.unregisterWindowListener("recipientsChangeWindowListener");
    }
  }

  detectRecipientsChange(window) {
    window.document.getElementById('recipientsContainer').addEventListener('change', function(event) {
      recipientsChangeWindowListener.handleEvent(event);
    });

    window.document.getElementById('msgSubject').addEventListener('focus', function(event) {
      recipientsChangeWindowListener.handleEvent(event);
    });

    window.document.getElementById('content-frame').addEventListener('focus', function(event){
      recipientsChangeWindowListener.handleEvent(event);
    });
  }
};<commit_msg>Fix compatibility with Thunderbird 85 beta<commit_after>/* eslint-disable object-shorthand */

// Get various parts of the WebExtension framework that we need.
var { ExtensionCommon } = ChromeUtils.import("resource://gre/modules/ExtensionCommon.jsm");

// You probably already know what this does.
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");

// This is the important part. It implements the functions and events defined in schema.json.
// The variable must have the same name you've been using so far, "myapi" in this case.
var compose_ext = class extends ExtensionCommon.ExtensionAPI {
  getAPI(context) {
    let { extension } = context;
    let { tabManager, windowManager } = extension;
    async function getTabWindow(tabId){
      return (await tabManager.get(tabId)).nativeTab;
    }
    return {
      // Again, this key must have the same name.
      compose_ext: {

        getCurrentLanguage: async function(tabId) {
          return (await getTabWindow(tabId)).document.documentElement.getAttribute("lang");
        },

        canSpellCheck: async function(tabId) {
          // todo: use tabId
          var window = await getTabWindow(tabId);
          return window.gSpellChecker && window.gSpellChecker.canSpellCheck && window.gSpellChecker.enabled;
        },

        setSpellCheckerLanguage: async function(tabId, lang) {
          var window = await getTabWindow(tabId);
          var fake_event = {
            target: {
              value: lang
            },
            stopPropagation: function(){}
          };
          return window.ChangeLanguage(fake_event);
        },

        showNotification: async function(tabId, string, options){
          options = options || {};
          var window = await getTabWindow(tabId);
          var notification_value = "show-message";
          //FIXME: DRY this code with changeLabel
          let nb = (window.gNotification && window.gNotification.notificationbox) || window.gComposeNotification;
          var n = nb.getNotificationWithValue(notification_value);
          if(n) {
            n.label = string;
          } else {
            var buttons = options.buttons || [];
            var priority = nb.PRIORITY_INFO_HIGH;
            n = nb.appendNotification(string, notification_value, options.logo_url, priority, buttons);
          }
          // setup timeout
          if (options.notification_time) {
            if(this.label_timeout){
              window.clearTimeout(this.label_timeout);
            }
            this.label_timeout = window.setTimeout( function(){
              nb.removeNotification( n );
            }, options.notification_time);
          }
        },

        // An event. Most of this is boilerplate you don't need to worry about, just copy it.
        onLanguageChange: new ExtensionCommon.EventManager({
          context,
          name: "compose_ext.onLanguageChange",
          // In this function we add listeners for any events we want to listen to, and return a
          // function that removes those listeners. To have the event fire in your extension,
          // call fire.async.
          register(fire) {
            function callback(event_name, event, language) {
              let win = windowManager.wrapWindow(event.target.ownerGlobal);
              var tab = tabManager.convert(win.activeTab.nativeTab);
              return fire.async(tab.id, language);
            }

            windowListener.add(callback);
            return function() {
              windowListener.remove(callback);
            };
          },
        }).api(),

        onRecipientsChange: new ExtensionCommon.EventManager({
          context,
          name: "compose_ext.onRecipientsChange",
          // In this function we add listeners for any events we want to listen to, and return a
          // function that removes those listeners. To have the event fire in your extension,
          // call fire.async.
          register(fire) {
            function callback(event_name, event) {
              let win = windowManager.wrapWindow(event.target.ownerGlobal);
              var tab = tabManager.convert(win.activeTab.nativeTab);
              return fire.async(tab.id);
            }

            recipientsChangeWindowListener.add(callback);
            return function() {
              recipientsChangeWindowListener.remove(callback);
            };
          },
        }).api(),

      },
    };
  }
};

// A helpful class for listening to windows opening and closing.
// (This file had a lowercase E in Thunderbird 65 and earlier.)
var { ExtensionSupport } = ChromeUtils.import("resource:///modules/ExtensionSupport.jsm");

// This object is just what we're using to listen for toolbar clicks. The implementation isn't
// what this example is about, but you might be interested as it's a common pattern. We count the
// number of callbacks waiting for events so that we're only listening if we need to be.
var windowListener = new class extends ExtensionCommon.EventEmitter {
  constructor() {
    super();
    this.callbackCount = 0;
  }

  handleEvent(event) {
    var lang = event.target.getAttribute('lang');
    windowListener.emit("language-changed", event, lang);
  }

  add(callback) {
    this.on("language-changed", callback);
    this.callbackCount++;

    if (this.callbackCount == 1) {
      ExtensionSupport.registerWindowListener("compose_ext-windowListener", {
        //TODO: set composer url.
        chromeURLs: ["chrome://messenger/content/messengercompose/messengercompose.xhtml"],
        onLoadWindow: function(window) {
          windowListener.subscribeLanguageChangeEvents(window);
        },
      });
    }
  }

  remove(callback) {
    this.off("language-changed", callback);
    this.callbackCount--;

    if (this.callbackCount == 0) {
      ExtensionSupport.unregisterWindowListener("compose_ext-windowListener");
    }
  }

  subscribeLanguageChangeEvents(window) {
    //We don't capture "spellcheck-changed" event because it's only fired
    //when language is changed in the context menu (rigt click menu). Not when changed
    //from any other source.

    // The document lang attribute is updated always so its the best way.
    var langObserver = new window.MutationObserver(function(mutations) {
      mutations.forEach(function(mutation) {
        if (mutation.type == "attributes" && mutation.attributeName == "lang") {
          windowListener.handleEvent(mutation);
        }
      });
    });
    langObserver.observe(window.document.documentElement, { attributes: true });
  }
};

var recipientsChangeWindowListener = new class extends ExtensionCommon.EventEmitter {
  constructor() {
    super();
    this.callbackCount = 0;
  }

  handleEvent(event) {
    recipientsChangeWindowListener.emit("recipients-changed", event);
  }

  add(callback) {
    this.on("recipients-changed", callback);
    this.callbackCount++;

    if (this.callbackCount == 1) {
      ExtensionSupport.registerWindowListener("recipientsChangeWindowListener", {
        chromeURLs: ["chrome://messenger/content/messengercompose/messengercompose.xhtml"],
        onLoadWindow: function(window) {
          recipientsChangeWindowListener.detectRecipientsChange(window);
        },
      });
    }
  }

  remove(callback) {
    this.off("recipients-changed", callback);
    this.callbackCount--;

    if (this.callbackCount == 0) {
      ExtensionSupport.unregisterWindowListener("recipientsChangeWindowListener");
    }
  }

  detectRecipientsChange(window) {
    window.document.getElementById('recipientsContainer').addEventListener('change', function(event) {
      recipientsChangeWindowListener.handleEvent(event);
    });

    window.document.getElementById('msgSubject').addEventListener('focus', function(event) {
      recipientsChangeWindowListener.handleEvent(event);
    });

    window.document.getElementById('content-frame').addEventListener('focus', function(event){
      recipientsChangeWindowListener.handleEvent(event);
    });
  }
};<|endoftext|>


<commit_before>import Component from 'ember-forge-ui/components/ef-nav/nav-list-link';

/**
 * @module
 * @augments ember-forge-ui/components/ef-nav/nav-list-link
 */
export default Component.extend({

  // -------------------------------------------------------------------------
  // Dependencies

  // -------------------------------------------------------------------------
  // Attributes

  /** @type {String[]} */
  classNameBindings: [
    'active',
    'disabled'
  ],

  /** @type {String[]} */
  classNames: [
    'nav-link'
  ]

  // -------------------------------------------------------------------------
  // Actions

  // -------------------------------------------------------------------------
  // Events

  // -------------------------------------------------------------------------
  // Properties

  // -------------------------------------------------------------------------
  // Observers

  // -------------------------------------------------------------------------
  // Methods

});
<commit_msg>Delete ef-nav/nav-list-link component<commit_after><|endoftext|>


<commit_before>
import Debug from 'debug'
import Portal from 'react-portal'
import React from 'react'
import SlateTypes from 'slate-prop-types'
import Types from 'prop-types'
import logger from 'slate-dev-logger'
import { Schema, Stack } from 'slate'

import EVENT_HANDLERS from '../constants/event-handlers'
import PLUGINS_PROPS from '../constants/plugin-props'
import AfterPlugin from '../plugins/after'
import BeforePlugin from '../plugins/before'
import noop from '../utils/noop'

/**
 * Debug.
 *
 * @type {Function}
 */

const debug = Debug('slate:editor')

/**
 * Editor.
 *
 * @type {Component}
 */

class Editor extends React.Component {

  /**
   * Property types.
   *
   * @type {Object}
   */

  static propTypes = {
    autoCorrect: Types.bool,
    autoFocus: Types.bool,
    className: Types.string,
    onChange: Types.func,
    placeholder: Types.any,
    plugins: Types.array,
    readOnly: Types.bool,
    role: Types.string,
    schema: Types.object,
    spellCheck: Types.bool,
    style: Types.object,
    tabIndex: Types.number,
    value: SlateTypes.value.isRequired,
  }

  /**
   * Default properties.
   *
   * @type {Object}
   */

  static defaultProps = {
    autoFocus: false,
    autoCorrect: true,
    onChange: noop,
    plugins: [],
    readOnly: false,
    schema: {},
    spellCheck: true,
  }

  /**
   * Constructor.
   *
   * @param {Object} props
   */

  constructor(props) {
    super(props)
    this.state = {}
    this.tmp = {}
    this.tmp.updates = 0
    this.tmp.resolves = 0

    // Resolve the plugins and create a stack and schema from them.
    const plugins = this.resolvePlugins(props.plugins, props.schema)
    const stack = Stack.create({ plugins })
    const schema = Schema.create({ plugins })
    this.state.schema = schema
    this.state.stack = stack

    // Run `onChange` on the passed-in value because we need to ensure that it
    // is normalized, and queue the resulting change.
    const change = props.value.change()
    stack.run('onChange', change, this)
    this.queueChange(change)
    this.state.value = change.value

    // Create a bound event handler for each event.
    EVENT_HANDLERS.forEach((handler) => {
      this[handler] = (...args) => {
        this.onEvent(handler, ...args)
      }
    })
  }

  /**
   * When the `props` are updated, create a new `Stack` if necessary and run
   * `onChange` to ensure the value is normalized.
   *
   * @param {Object} props
   */

  componentWillReceiveProps = (props) => {
    let { schema, stack } = this

    // Increment the updates counter as a baseline.
    this.tmp.updates++

    // If the plugins or the schema have changed, we need to re-resolve the
    // plugins, since it will result in a new stack and new validations.
    if (props.plugins != this.props.plugins || props.schema != this.props.schema) {
      const plugins = this.resolvePlugins(props.plugins, props.schema)
      stack = Stack.create({ plugins })
      schema = Schema.create({ plugins })
      this.setState({ schema, stack })

      // Increment the resolves counter.
      this.tmp.resolves++

      // If we've resolved a few times already, and it's exactly in line with
      // the updates, then warn the user that they may be doing something wrong.
      if (this.tmp.resolves > 5 && this.tmp.resolves == this.tmp.updates) {
        logger.warn('A Slate <Editor> is re-resolving `props.plugins` or `props.schema` on each update, which leads to poor performance. This is often due to passing in a new `schema` or `plugins` prop with each render by declaring them inline in your render function. Do not do this!')
      }
    }

    // Run `onChange` on the passed-in value because we need to ensure that it
    // is normalized, and queue the resulting change.
    const change = props.value.change()
    stack.run('onChange', change, this)
    this.queueChange(change)
    this.setState({ value: change.value })
  }

  /**
   * When the component first mounts, flush any temporary changes.
   */

  componentDidMount = () => {
    this.flushChange()
  }

  /**
   * When the component updates, flush any temporary change.
   */

  componentDidUpdate = () => {
    this.flushChange()
  }

  /**
   * Queue a `change` object, to be able to flush it later. This is required for
   * when a change needs to be applied to the value, but because of the React
   * lifecycle we can't apply that change immediately. So we cache it here and
   * later can call `this.flushChange()` to flush it.
   *
   * @param {Change} change
   */

  queueChange = (change) => {
    if (change.operations.length) {
      debug('queueChange', { change })
      this.tmp.change = change
    }
  }

  /**
   * Flush a temporarily stored `change` object, for when a change needed to be
   * made but couldn't because of React's lifecycle.
   */

  flushChange = () => {
    const { change } = this.tmp

    if (change) {
      debug('flushChange', { change })
      window.requestAnimationFrame(() => {
        delete this.tmp.change
        this.props.onChange(change)
      })
    }
  }

  /**
   * Perform a change on the editor, passing `...args` to `change.call`.
   *
   * @param {Mixed} ...args
   */

  change = (...args) => {
    const change = this.value.change().call(...args)
    this.onChange(change)
  }

  /**
   * Programmatically blur the editor.
   */

  blur = () => {
    this.change(c => c.blur())
  }

  /**
   * Programmatically focus the editor.
   */

  focus = () => {
    this.change(c => c.focus())
  }

  /**
   * Getters for exposing public properties of the editor's state.
   */

  get schema() {
    return this.state.schema
  }

  get stack() {
    return this.state.stack
  }

  get value() {
    return this.state.value
  }

  /**
   * On event.
   *
   * @param {String} handler
   * @param {Event} event
   */

  onEvent = (handler, event) => {
    this.change((change) => {
      this.stack.run(handler, event, change, this)
    })
  }

  /**
   * On change.
   *
   * @param {Change} change
   */

  onChange = (change) => {
    debug('onChange', { change })

    this.stack.run('onChange', change, this)
    const { value } = change
    const { onChange } = this.props
    if (value == this.value) return
    onChange(change)
  }

  /**
   * Render the editor.
   *
   * @return {Element}
   */

  render() {
    debug('render', this)

    const children = this.stack
      .map('renderPortal', this.value, this)
      .map((child, i) => <Portal key={i} isOpened>{child}</Portal>)

    const props = { ...this.props, children }
    const tree = this.stack.render('renderEditor', props, this)
    return tree
  }

  /**
   * Resolve an array of plugins from `plugins` and `schema` props.
   *
   * In addition to the plugins provided in props, this will initialize three
   * other plugins:
   *
   * - The top-level editor plugin, which allows for top-level handlers, etc.
   * - The two "core" plugins, one before all the other and one after.
   *
   * @param {Array|Void} plugins
   * @param {Schema|Object|Void} schema
   * @return {Array}
   */

  resolvePlugins = (plugins, schema) => {
    const beforePlugin = BeforePlugin()
    const afterPlugin = AfterPlugin()
    const editorPlugin = {
      schema: schema || {}
    }

    for (const prop of PLUGINS_PROPS) {
      // Skip `onChange` because the editor's `onChange` is special.
      if (prop == 'onChange') continue

      // Skip `schema` because it can't be proxied easily, so it must be
      // passed in as an argument to this function instead.
      if (prop == 'schema') continue

      // Define a function that will just proxies into `props`.
      editorPlugin[prop] = (...args) => {
        return this.props[prop] && this.props[prop](...args)
      }
    }

    return [
      beforePlugin,
      editorPlugin,
      ...(plugins || []),
      afterPlugin
    ]
  }

}

/**
 * Mix in the property types for the event handlers.
 */

for (const prop of EVENT_HANDLERS) {
  Editor.propTypes[prop] = Types.func
}

/**
 * Export.
 *
 * @type {Component}
 */

export default Editor
<commit_msg>fix flush change logic to not stack flushes (#1324)<commit_after>
import Debug from 'debug'
import Portal from 'react-portal'
import React from 'react'
import SlateTypes from 'slate-prop-types'
import Types from 'prop-types'
import logger from 'slate-dev-logger'
import { Schema, Stack } from 'slate'

import EVENT_HANDLERS from '../constants/event-handlers'
import PLUGINS_PROPS from '../constants/plugin-props'
import AfterPlugin from '../plugins/after'
import BeforePlugin from '../plugins/before'
import noop from '../utils/noop'

/**
 * Debug.
 *
 * @type {Function}
 */

const debug = Debug('slate:editor')

/**
 * Editor.
 *
 * @type {Component}
 */

class Editor extends React.Component {

  /**
   * Property types.
   *
   * @type {Object}
   */

  static propTypes = {
    autoCorrect: Types.bool,
    autoFocus: Types.bool,
    className: Types.string,
    onChange: Types.func,
    placeholder: Types.any,
    plugins: Types.array,
    readOnly: Types.bool,
    role: Types.string,
    schema: Types.object,
    spellCheck: Types.bool,
    style: Types.object,
    tabIndex: Types.number,
    value: SlateTypes.value.isRequired,
  }

  /**
   * Default properties.
   *
   * @type {Object}
   */

  static defaultProps = {
    autoFocus: false,
    autoCorrect: true,
    onChange: noop,
    plugins: [],
    readOnly: false,
    schema: {},
    spellCheck: true,
  }

  /**
   * Constructor.
   *
   * @param {Object} props
   */

  constructor(props) {
    super(props)
    this.state = {}
    this.tmp = {}
    this.tmp.updates = 0
    this.tmp.resolves = 0

    // Resolve the plugins and create a stack and schema from them.
    const plugins = this.resolvePlugins(props.plugins, props.schema)
    const stack = Stack.create({ plugins })
    const schema = Schema.create({ plugins })
    this.state.schema = schema
    this.state.stack = stack

    // Run `onChange` on the passed-in value because we need to ensure that it
    // is normalized, and queue the resulting change.
    const change = props.value.change()
    stack.run('onChange', change, this)
    this.queueChange(change)
    this.state.value = change.value

    // Create a bound event handler for each event.
    EVENT_HANDLERS.forEach((handler) => {
      this[handler] = (...args) => {
        this.onEvent(handler, ...args)
      }
    })
  }

  /**
   * When the `props` are updated, create a new `Stack` if necessary and run
   * `onChange` to ensure the value is normalized.
   *
   * @param {Object} props
   */

  componentWillReceiveProps = (props) => {
    let { schema, stack } = this

    // Increment the updates counter as a baseline.
    this.tmp.updates++

    // If the plugins or the schema have changed, we need to re-resolve the
    // plugins, since it will result in a new stack and new validations.
    if (props.plugins != this.props.plugins || props.schema != this.props.schema) {
      const plugins = this.resolvePlugins(props.plugins, props.schema)
      stack = Stack.create({ plugins })
      schema = Schema.create({ plugins })
      this.setState({ schema, stack })

      // Increment the resolves counter.
      this.tmp.resolves++

      // If we've resolved a few times already, and it's exactly in line with
      // the updates, then warn the user that they may be doing something wrong.
      if (this.tmp.resolves > 5 && this.tmp.resolves == this.tmp.updates) {
        logger.warn('A Slate <Editor> is re-resolving `props.plugins` or `props.schema` on each update, which leads to poor performance. This is often due to passing in a new `schema` or `plugins` prop with each render by declaring them inline in your render function. Do not do this!')
      }
    }

    // Run `onChange` on the passed-in value because we need to ensure that it
    // is normalized, and queue the resulting change.
    const change = props.value.change()
    stack.run('onChange', change, this)
    this.queueChange(change)
    this.setState({ value: change.value })
  }

  /**
   * When the component first mounts, flush any temporary changes.
   */

  componentDidMount = () => {
    this.flushChange()
  }

  /**
   * When the component updates, flush any temporary change.
   */

  componentDidUpdate = () => {
    this.flushChange()
  }

  /**
   * Queue a `change` object, to be able to flush it later. This is required for
   * when a change needs to be applied to the value, but because of the React
   * lifecycle we can't apply that change immediately. So we cache it here and
   * later can call `this.flushChange()` to flush it.
   *
   * @param {Change} change
   */

  queueChange = (change) => {
    if (change.operations.length) {
      debug('queueChange', { change })
      this.tmp.change = change
    }
  }

  /**
   * Flush a temporarily stored `change` object, for when a change needed to be
   * made but couldn't because of React's lifecycle.
   */

  flushChange = () => {
    const { change } = this.tmp

    if (change && !this.tmp.flushTimeout) {
      debug('flushChange', { change })
      this.tmp.flushTimeout = setTimeout(() => {
        delete this.tmp.change
        delete this.tmp.flushTimeout
        this.props.onChange(change)
      })
    }
  }

  /**
   * Perform a change on the editor, passing `...args` to `change.call`.
   *
   * @param {Mixed} ...args
   */

  change = (...args) => {
    const change = this.value.change().call(...args)
    this.onChange(change)
  }

  /**
   * Programmatically blur the editor.
   */

  blur = () => {
    this.change(c => c.blur())
  }

  /**
   * Programmatically focus the editor.
   */

  focus = () => {
    this.change(c => c.focus())
  }

  /**
   * Getters for exposing public properties of the editor's state.
   */

  get schema() {
    return this.state.schema
  }

  get stack() {
    return this.state.stack
  }

  get value() {
    return this.state.value
  }

  /**
   * On event.
   *
   * @param {String} handler
   * @param {Event} event
   */

  onEvent = (handler, event) => {
    this.change((change) => {
      this.stack.run(handler, event, change, this)
    })
  }

  /**
   * On change.
   *
   * @param {Change} change
   */

  onChange = (change) => {
    debug('onChange', { change })

    this.stack.run('onChange', change, this)
    const { value } = change
    const { onChange } = this.props
    if (value == this.value) return
    onChange(change)
  }

  /**
   * Render the editor.
   *
   * @return {Element}
   */

  render() {
    debug('render', this)

    const children = this.stack
      .map('renderPortal', this.value, this)
      .map((child, i) => <Portal key={i} isOpened>{child}</Portal>)

    const props = { ...this.props, children }
    const tree = this.stack.render('renderEditor', props, this)
    return tree
  }

  /**
   * Resolve an array of plugins from `plugins` and `schema` props.
   *
   * In addition to the plugins provided in props, this will initialize three
   * other plugins:
   *
   * - The top-level editor plugin, which allows for top-level handlers, etc.
   * - The two "core" plugins, one before all the other and one after.
   *
   * @param {Array|Void} plugins
   * @param {Schema|Object|Void} schema
   * @return {Array}
   */

  resolvePlugins = (plugins, schema) => {
    const beforePlugin = BeforePlugin()
    const afterPlugin = AfterPlugin()
    const editorPlugin = {
      schema: schema || {}
    }

    for (const prop of PLUGINS_PROPS) {
      // Skip `onChange` because the editor's `onChange` is special.
      if (prop == 'onChange') continue

      // Skip `schema` because it can't be proxied easily, so it must be
      // passed in as an argument to this function instead.
      if (prop == 'schema') continue

      // Define a function that will just proxies into `props`.
      editorPlugin[prop] = (...args) => {
        return this.props[prop] && this.props[prop](...args)
      }
    }

    return [
      beforePlugin,
      editorPlugin,
      ...(plugins || []),
      afterPlugin
    ]
  }

}

/**
 * Mix in the property types for the event handlers.
 */

for (const prop of EVENT_HANDLERS) {
  Editor.propTypes[prop] = Types.func
}

/**
 * Export.
 *
 * @type {Component}
 */

export default Editor
<|endoftext|>


<commit_before>function ResolverIntercept(resolver) {
  this.resolver = resolver;
  this.cache = {};
};

ResolverIntercept.prototype.require = function(import_path) {
  // Modify import_path so the cache key is consistently the same irrespective
  // of whether a user explicated .sol extension
  import_path = import_path.replace(/\.sol$/i, '');

  // TODO: Using the import path for relative files may result in multiple
  // paths for the same file. This could return different objects since it won't be a cache hit.
  if (this.cache[import_path]) {
    return this.cache[import_path];
  }

  // Note, will error if nothing is found.
  var resolved = this.resolver.require(import_path);

  this.cache[import_path] = resolved;

  // During migrations, we could be on a network that takes a long time to accept
  // transactions (i.e., contract deployment close to block size). Because successful
  // migration is more important than wait time in those cases, we'll synchronize "forever".
  resolved.synchronization_timeout = 0;

  return resolved;
};

ResolverIntercept.prototype.contracts = function() {
  var self = this;
  return Object.keys(this.cache).map(function(key) {
    return self.cache[key];
  });
};

module.exports = ResolverIntercept;
<commit_msg>Use only contract name for migrate require cache<commit_after>const path = require("path");

function ResolverIntercept(resolver) {
  this.resolver = resolver;
  this.cache = {};
};

ResolverIntercept.prototype.require = function(import_path) {
  // Modify import_path so the cache key is consistently based only on the contract name.
  // This works because Truffle already prevents more than one contract with the same name.
  // Ref: https://github.com/trufflesuite/truffle/issues/1087
  import_path = path.basename(import_path).replace(/\.sol$/i, '');

  // TODO: Using the import path for relative files may result in multiple
  // paths for the same file. This could return different objects since it won't be a cache hit.
  if (this.cache[import_path]) {
    return this.cache[import_path];
  }

  // Note, will error if nothing is found.
  var resolved = this.resolver.require(import_path);

  this.cache[import_path] = resolved;

  // During migrations, we could be on a network that takes a long time to accept
  // transactions (i.e., contract deployment close to block size). Because successful
  // migration is more important than wait time in those cases, we'll synchronize "forever".
  resolved.synchronization_timeout = 0;

  return resolved;
};

ResolverIntercept.prototype.contracts = function() {
  var self = this;
  return Object.keys(this.cache).map(function(key) {
    return self.cache[key];
  });
};

module.exports = ResolverIntercept;
<|endoftext|>


<commit_before>const path = require('path')

const {
  getPlatforms,
  normalizePath
} = require('@dcloudio/uni-cli-shared')

const PLATFORMS = getPlatforms()

const alipayWindowMap = {
  'defaultTitle': 'navigationBarTitleText',
  'pullRefresh': 'enablePullDownRefresh',
  'allowsBounceVertical': 'allowsBounceVertical',
  'titleBarColor': 'navigationBarBackgroundColor',
  'optionMenu': 'optionMenu',
  'backgroundColor': 'backgroundColor',
  'usingComponents': 'usingComponents',
  'navigationBarShadow': 'navigationBarShadow',
  'titleImage': 'titleImage'
}

const alipayTabBarMap = {
  'textColor': 'color',
  'selectedColor': 'selectedColor',
  'backgroundColor': 'backgroundColor',
  'items': 'list'
}

const alipayTabBarItemMap = {
  'pagePath': 'pagePath',
  'name': 'text',
  'icon': 'iconPath',
  'activeIcon': 'selectedIconPath'
}

function hasOwn (obj, key) {
  return hasOwnProperty.call(obj, key)
}

function parseStyle (style = {}, root = '') {
  // TODO pages.json 触发了两次，需要排查
  style = JSON.parse(JSON.stringify(style))

  let platformStyle = {}

  Object.keys(style).forEach(name => {
    if (PLATFORMS.includes(name)) {
      if (name === process.env.UNI_PLATFORM) {
        platformStyle = style[name] || {}
      }
      delete style[name]
    }
  })

  if (root && process.env.UNI_PLATFORM === 'app-plus') { // 处理分包逻辑
    if (Array.isArray(platformStyle.subNVues) && platformStyle.subNVues.length) {
      platformStyle.subNVues.forEach(subNVue => {
        subNVue.path = normalizePath(path.join(root, subNVue.path))
      })
    }
  }

  if (process.env.UNI_PLATFORM === 'mp-alipay') {
    const windowOptions = {}
    Object.keys(alipayWindowMap).forEach(key => {
      if (hasOwn(style, alipayWindowMap[key])) {
        windowOptions[key] = style[alipayWindowMap[key]]
      }
    })
    return Object.assign(windowOptions, platformStyle)
  }

  if (style.navigationBarTextStyle && style.navigationBarTextStyle !== 'black') {
    style.navigationBarTextStyle = 'white'
  }

  return Object.assign({
    usingComponents: {}
  }, style, platformStyle)
}

function parseTabBar (style = {}) {
  if (process.env.UNI_PLATFORM === 'mp-alipay') {
    const tabBarOptions = {}
    Object.keys(alipayTabBarMap).forEach(key => {
      if (hasOwn(style, alipayTabBarMap[key])) {
        tabBarOptions[key] = style[alipayTabBarMap[key]]
      }
    })
    if (Array.isArray(tabBarOptions.items) && tabBarOptions.items.length) {
      tabBarOptions.items = tabBarOptions.items.map(itemOptions => {
        const tabBarItemOptions = {}
        Object.keys(alipayTabBarItemMap).forEach(key => {
          if (hasOwn(itemOptions, alipayTabBarItemMap[key])) {
            tabBarItemOptions[key] = itemOptions[alipayTabBarItemMap[key]]
          }
        })
        return tabBarItemOptions
      })
    }
    return tabBarOptions
  }

  return style
}

module.exports = {
  hasOwn,
  parseStyle,
  parseTabBar
}
<commit_msg>update: 增加通用配置拷贝到支付宝<commit_after>const path = require('path')

const {
  getPlatforms,
  normalizePath
} = require('@dcloudio/uni-cli-shared')

const PLATFORMS = getPlatforms()

const alipayWindowMap = {
  'defaultTitle': 'navigationBarTitleText',
  'pullRefresh': 'enablePullDownRefresh',
  'allowsBounceVertical': 'allowsBounceVertical',
  'titleBarColor': 'navigationBarBackgroundColor',
  'optionMenu': 'optionMenu',
  'backgroundColor': 'backgroundColor',
  'usingComponents': 'usingComponents',
  'navigationBarShadow': 'navigationBarShadow',
  'titleImage': 'titleImage',
  'transparentTitle': 'transparentTitle',
  'titlePenetrate': 'titlePenetrate'
}

const alipayTabBarMap = {
  'textColor': 'color',
  'selectedColor': 'selectedColor',
  'backgroundColor': 'backgroundColor',
  'items': 'list'
}

const alipayTabBarItemMap = {
  'pagePath': 'pagePath',
  'name': 'text',
  'icon': 'iconPath',
  'activeIcon': 'selectedIconPath'
}

function hasOwn (obj, key) {
  return hasOwnProperty.call(obj, key)
}

function parseStyle (style = {}, root = '') {
  // TODO pages.json 触发了两次，需要排查
  style = JSON.parse(JSON.stringify(style))

  let platformStyle = {}

  Object.keys(style).forEach(name => {
    if (PLATFORMS.includes(name)) {
      if (name === process.env.UNI_PLATFORM) {
        platformStyle = style[name] || {}
      }
      delete style[name]
    }
  })

  if (root && process.env.UNI_PLATFORM === 'app-plus') { // 处理分包逻辑
    if (Array.isArray(platformStyle.subNVues) && platformStyle.subNVues.length) {
      platformStyle.subNVues.forEach(subNVue => {
        subNVue.path = normalizePath(path.join(root, subNVue.path))
      })
    }
  }

  if (process.env.UNI_PLATFORM === 'mp-alipay') {
    const windowOptions = {}
    Object.keys(alipayWindowMap).forEach(key => {
      if (hasOwn(style, alipayWindowMap[key])) {
        windowOptions[key] = style[alipayWindowMap[key]]
      }
    })
    return Object.assign(windowOptions, platformStyle)
  }

  if (style.navigationBarTextStyle && style.navigationBarTextStyle !== 'black') {
    style.navigationBarTextStyle = 'white'
  }

  return Object.assign({
    usingComponents: {}
  }, style, platformStyle)
}

function parseTabBar (style = {}) {
  if (process.env.UNI_PLATFORM === 'mp-alipay') {
    const tabBarOptions = {}
    Object.keys(alipayTabBarMap).forEach(key => {
      if (hasOwn(style, alipayTabBarMap[key])) {
        tabBarOptions[key] = style[alipayTabBarMap[key]]
      }
    })
    if (Array.isArray(tabBarOptions.items) && tabBarOptions.items.length) {
      tabBarOptions.items = tabBarOptions.items.map(itemOptions => {
        const tabBarItemOptions = {}
        Object.keys(alipayTabBarItemMap).forEach(key => {
          if (hasOwn(itemOptions, alipayTabBarItemMap[key])) {
            tabBarItemOptions[key] = itemOptions[alipayTabBarItemMap[key]]
          }
        })
        return tabBarItemOptions
      })
    }
    return tabBarOptions
  }

  return style
}

module.exports = {
  hasOwn,
  parseStyle,
  parseTabBar
}
<|endoftext|>


<commit_before>console.log( "==== simpread options page load ====" )

import '../assets/css/options.css';

import Tabs from 'tabs';

const tabsitem = [{
        name: "共通",
        value: "common",
        icon : "",
        active : true,
        disable: false,
        route: ""
    },{
        name: "聚焦模式",
        value: "focus",
        icon : "",
        active : false,
        disable: false,
        route: ""
    },{
        name: "阅读模式",
        value: "read",
        icon : "",
        active : false,
        disable: false,
        route: ""
    },{
        name: "稍后读",
        value: "later",
        icon : "",
        active : false,
        disable: false,
        route: ""
}];

/**
 * Add parallax scroll
 */
$( window ).scroll( (event) => {
    const $target = $( event.target ),
          offset  = ( 0 - $target.scrollTop() ) / 2;
    $( ".top" ).css( "transform", `translate3d(0px, ${offset}px, 0px)` )
});

/**
 * Tabs onChange event handler
 *
 * @param {jquery} prev jquery object
 * @param {event} current event
 */
function tabsOnChange( $prev, event ) {
    console.log( $prev, event )
}

/**
 * Render Tabs
 */
const tabs =
    <Tabs items={ tabsitem } bgColor="rgb(153,204,255)" onChange={ ( $p, evt )=>tabsOnChange( $p, evt ) }>

aaa

bbb

ccc

ddd

    </Tabs>;
ReactDOM.render( tabs, $( ".tabscontainer" )[0] );<commit_msg>Format source.<commit_after>console.log( "==== simpread options page load ====" )

import '../assets/css/options.css';

import Tabs from 'tabs';

const tabsitem = [{
        name: "共通",
        value: "common",
        icon : "",
        active : true,
    },{
        name: "聚焦模式",
        value: "focus",
        icon : "",
    },{
        name: "阅读模式",
        value: "read",
        icon : "",
    },{
        name: "稍后读",
        value: "later",
        icon : "",
}];

/**
 * Add parallax scroll
 */
$( window ).scroll( (event) => {
    const $target = $( event.target ),
          offset  = ( 0 - $target.scrollTop() ) / 2;
    $( ".top" ).css( "transform", `translate3d(0px, ${offset}px, 0px)` )
});

/**
 * Tabs onChange event handler
 *
 * @param {jquery} prev jquery object
 * @param {event} current event
 */
function tabsOnChange( $prev, event ) {
    console.log( $prev, event )
}

/**
 * Render Tabs
 */
const tabs =
    <Tabs items={ tabsitem } bgColor="rgb(153,204,255)" onChange={ ( $p, evt )=>tabsOnChange( $p, evt ) }>

aaa

bbb

ccc

ddd

    </Tabs>;
ReactDOM.render( tabs, $( ".tabscontainer" )[0] );<|endoftext|>


<commit_before>'use strict';

let Line = require("./service/line");

module.exports = class VirtualPlatform {
    constructor(options){
        this.type = options.message_platform_type;
        this.options = options;
        this.service = this.instantiate_service();
    }

    instantiate_service(){
        return this[`_${this.type}_instantiate_service`]();
    }

    _line_instantiate_service(){
        return new Line(this.options.line_channel_id, this.options.line_channel_secret, this.options.line_channel_access_token);
    }

    validate_signature(signature, raw_body){
        return this[`_${this.type}_validate_signature`]();
    }

    _line_validate_signature(signature, raw_body){
        if (!this.service.validate_signature(signature, raw_body)){
            throw(`Signature Validation failed.`);
        }
    }

    extract_event(body){
        return this[`_${this.type}_extract_event`](body);
    }

    _line_extract_event(body){
        return body.events;
    }

    extract_memory_id(bot_event){
        return this[`_${this.type}_extract_memory_id`](bot_event);
    }

    _line_extract_memory_id(bot_event){
        return bot_event.source.userId;
    }

    check_supported_event_type(flow, bot_event){
        return this[`_${this.type}_check_supported_event_type`](flow, bot_event);
    }

    _line_check_supported_event_type(flow, bot_event){
        switch(flow){
            case "start_conversation":
                if (bot_event.type == "message" && bot_event.message.type == "text"){
                    return true;
                }
                return false;
            break;
            case "reply":
                if ((bot_event.type == "message" && bot_event.message.type == "text") || bot_event.type == "postback"){
                    return true;
                }
                return false;
            break;
            case "change_intent":
                if (bot_event.type == "message" && bot_event.message.type == "text"){
                    return true;
                }
                return false;
            break;
            case "change_parameter":
                if ((bot_event.type == "message" && bot_event.message.type == "text") || bot_event.type == "postback"){
                    return true;
                }
                return false;
            break;
            case "no_way":
                if (bot_event.type == "message" && bot_event.message.type == "text"){
                    return true;
                }
                return false;
            break;
            default:
                return false;
            break;
        }
    }

    extract_session_id(bot_event){
        return this[`_${this.type}_extract_session_id`](bot_event);
    }

    _line_extract_session_id(bot_event){
        return bot_event.source.userId;
    }

    extract_message_text(bot_event){
        return this[`_${this.type}_extract_message_text`](bot_event);
    }

    _line_extract_message_text(bot_event){
        let message_text;
        switch(bot_event.type){
            case "message":
                message_text = bot_event.message.text;
            break;
            case "postback":
                message_text = bot_event.postback.data;
            break;
        }
        return message_text;
    }

    create_message(message_object, message_type){
        return this[`_${this.type}_create_message`](message_object, message_type);
    }

    _line_create_message(message_object, message_type = "text"){
        let message;
        switch(message_type){
            case "text":
                message = {
                    type: "text",
                    text: message_object
                }
            break;
        }
        return message;
    }

    reply(bot_event, messages){
        return this[`_${this.type}_reply`](bot_event, messages);
    }

    _line_reply(bot_event, messages){
        return this.service.reply(bot_event.replyToken, messages);
    }
}
<commit_msg>introduced virtual platform<commit_after>'use strict';

let Line = require("./service/line");

module.exports = class VirtualPlatform {
    constructor(options){
        this.type = options.message_platform_type;
        this.options = options;
        this.service = this.instantiate_service();
    }

    instantiate_service(){
        return this[`_${this.type}_instantiate_service`]();
    }

    _line_instantiate_service(){
        return new Line(this.options.line_channel_id, this.options.line_channel_secret, this.options.line_channel_access_token);
    }

    validate_signature(signature, raw_body){
        return this[`_${this.type}_validate_signature`]();
    }

    _line_validate_signature(signature, raw_body){
        console.log(signature, raw_body);
        if (!this.service.validate_signature(signature, raw_body)){
            throw(`Signature Validation failed.`);
        }
    }

    extract_event(body){
        return this[`_${this.type}_extract_event`](body);
    }

    _line_extract_event(body){
        return body.events;
    }

    extract_memory_id(bot_event){
        return this[`_${this.type}_extract_memory_id`](bot_event);
    }

    _line_extract_memory_id(bot_event){
        return bot_event.source.userId;
    }

    check_supported_event_type(flow, bot_event){
        return this[`_${this.type}_check_supported_event_type`](flow, bot_event);
    }

    _line_check_supported_event_type(flow, bot_event){
        switch(flow){
            case "start_conversation":
                if (bot_event.type == "message" && bot_event.message.type == "text"){
                    return true;
                }
                return false;
            break;
            case "reply":
                if ((bot_event.type == "message" && bot_event.message.type == "text") || bot_event.type == "postback"){
                    return true;
                }
                return false;
            break;
            case "change_intent":
                if (bot_event.type == "message" && bot_event.message.type == "text"){
                    return true;
                }
                return false;
            break;
            case "change_parameter":
                if ((bot_event.type == "message" && bot_event.message.type == "text") || bot_event.type == "postback"){
                    return true;
                }
                return false;
            break;
            case "no_way":
                if (bot_event.type == "message" && bot_event.message.type == "text"){
                    return true;
                }
                return false;
            break;
            default:
                return false;
            break;
        }
    }

    extract_session_id(bot_event){
        return this[`_${this.type}_extract_session_id`](bot_event);
    }

    _line_extract_session_id(bot_event){
        return bot_event.source.userId;
    }

    extract_message_text(bot_event){
        return this[`_${this.type}_extract_message_text`](bot_event);
    }

    _line_extract_message_text(bot_event){
        let message_text;
        switch(bot_event.type){
            case "message":
                message_text = bot_event.message.text;
            break;
            case "postback":
                message_text = bot_event.postback.data;
            break;
        }
        return message_text;
    }

    create_message(message_object, message_type){
        return this[`_${this.type}_create_message`](message_object, message_type);
    }

    _line_create_message(message_object, message_type = "text"){
        let message;
        switch(message_type){
            case "text":
                message = {
                    type: "text",
                    text: message_object
                }
            break;
        }
        return message;
    }

    reply(bot_event, messages){
        return this[`_${this.type}_reply`](bot_event, messages);
    }

    _line_reply(bot_event, messages){
        return this.service.reply(bot_event.replyToken, messages);
    }
}
<|endoftext|>


<commit_before>function Resource(attributes) {
  this.id = attributes.id
  this.title = attributes.title
  this.url = attributes.url
  this.description = attributes.description
  this.user_id = attributes.user_id
  this.tags = attributes.tags
  this.languages = attributes.languages
}

Resource.ready = function () {
  Resource.assignListeners()
}

Resource.assignListeners = function () {
  Resource.yourResourcesListener()
}

Resource.yourResourcesListener = function () {
  $("a#js_resources").one("click", Resource.getResourcesAPI)
}

Resource.getResourcesAPI = function (e) {
  var $id = $(this).data("id")
  e.preventDefault()
  $.get(`/users/${$id}/resources`, Resource.success, "json").error(Resource.error)
}

Resource.success = function (json) {
  var resources = json.map(function (resource) {
    return new Resource(resource)
  })
  var $ul = $("#resource_list").empty()

  resources.forEach(Resource.renderLI)
}

Resource.renderLI = function (resource) {
  var li = resource.formatListItems()
  $("#resource_list").append(li)
}

Resource.prototype.formatListItems = function () {
  return `

    ${this.title}
     -
    ${this.tags.map(Tag.renderLink).join(" / ")}

    (${this.languages.map(Language.renderLink).join(", ")})

`
};

Resource.error = function (response) {
  console.log("You broke it!", response)
}

$(function () {
  Resource.ready()
})
<commit_msg>Fix Resource formatting js.<commit_after>function Resource(attributes) {
  this.id = attributes.id
  this.title = attributes.title
  this.url = attributes.url
  this.description = attributes.description
  this.user_id = attributes.user_id
  this.tags = attributes.tags
  this.languages = attributes.languages
}

Resource.ready = function () {
  Resource.assignListeners()
}

Resource.assignListeners = function () {
  Resource.yourResourcesListener()
}

Resource.yourResourcesListener = function () {
  $("a#js_resources").one("click", Resource.getResourcesAPI)
}

Resource.getResourcesAPI = function (e) {
  var $id = $(this).data("id")
  e.preventDefault()
  $.get(`/users/${$id}/resources`, Resource.success, "json").error(Resource.error)
}

Resource.success = function (json) {
  var resources = json.map(function (resource) {
    return new Resource(resource)
  })
  var $ul = $("#resource_list").empty()

  resources.forEach(Resource.renderLI)
}

Resource.renderLI = function (resource) {
  var li = resource.formatListItems()
  $("#resource_list").append(li)
}

Resource.prototype.formatListItems = function () {
  return `

    ${this.title}

    (${this.languages.map(Language.renderLink).join(", ")}) -
    ${this.tags.map(Tag.renderLink).join(" / ")}

`
};

Resource.error = function (response) {
  console.log("You broke it!", response)
}

$(function () {
  Resource.ready()
})
<|endoftext|>


<commit_before>(function(window, angular) {'use strict';
    var app = angular.module('advanced-search', ['fields']);

    app.controller('AdvancedSearchController', ['$rootScope', function($rootScope) {
        this.emptyKey = false;
        this.operator = 'AND';
        this.keyword = '';

        this.addField = function() {
            var actualOperator = '',
                expr;

            if (this.field && (this.keyword || this.emptyKey)) {
                expr = this.emptyKey ?
                    '-' + this.field + ':' + '["" TO *]' :
                    this.field + ':(*' + this.keyword + '*)';

                if ($rootScope.query && $rootScope.query.trim() !== '') {
                    actualOperator = ' ' + (this.emptyKey ? 'AND' : this.operator) + ' ';
                }

                $rootScope.query += actualOperator + expr;

                this.keyword = '';
            }
        };
    }]);

    app.directive('advancedSearch', function() {
        return {
            restrict: 'E',
            templateUrl: 'templates/advanced-search.html',
            controller: 'AdvancedSearchController',
            controllerAs: 'advSrchCtrl'
        };
    });

    /* Trim Poyfill:
     * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/Trim
     */
    if (!String.prototype.trim) {
        (function() {
            // Make sure we trim BOM and NBSP
            var rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;
            String.prototype.trim = function() {
                return this.replace(rtrim, '');
            };
        })();
    }

})(window, angular);
<commit_msg>Fixed the advanced field search<commit_after>(function(window, angular) {'use strict';
    var app = angular.module('advanced-search', ['fields']);

    app.controller('AdvancedSearchController', ['$rootScope', function($rootScope) {
        this.emptyKey = false;
        this.operator = 'AND';
        this.keyword = '';

        this.addField = function() {
            var actualOperator = '',
                expr;

            if (this.field && (this.keyword || this.emptyKey)) {
                expr = this.emptyKey ?
                    '-' + this.field + ':' + '["" TO *]' :
                    this.field + ':(' + this.keyword + ')';

                if ($rootScope.query && $rootScope.query.trim() !== '') {
                    actualOperator = ' ' + (this.emptyKey ? 'AND' : this.operator) + ' ';
                }

                $rootScope.query += actualOperator + expr;

                this.keyword = '';
            }
        };
    }]);

    app.directive('advancedSearch', function() {
        return {
            restrict: 'E',
            templateUrl: 'templates/advanced-search.html',
            controller: 'AdvancedSearchController',
            controllerAs: 'advSrchCtrl'
        };
    });

    /* Trim Poyfill:
     * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/Trim
     */
    if (!String.prototype.trim) {
        (function() {
            // Make sure we trim BOM and NBSP
            var rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;
            String.prototype.trim = function() {
                return this.replace(rtrim, '');
            };
        })();
    }

})(window, angular);
<|endoftext|>


<commit_before>var require = (function() {
  // function copied from creationix/path.js
  function join(/* path segments */) {
    var parts = [];
    for (var i = 0, l = arguments.length; i < l; i++) {
      parts = parts.concat(arguments[i].split("/"));
    }
    var newParts = [];
    for (i = 0, l = parts.length; i < l; i++) {
      var part = parts[i];
      if (!part || part === ".") continue;
      if (part === "..") newParts.pop();
      else newParts.push(part);
    }
    if (parts[0] === "") newParts.unshift("");
    return newParts.join("/") || (newParts.length ? "/" : ".");
  }

  var modules = {};

  class Module {
    constructor(url) {
      this.loaded = false;

      this.filename = url;
      this.dirname = join(url, '..');

      this.children = [];
      this.require = [];
      this.prepare = imports => null,
      this.exports = {};
    }

    addChildren(module) {
      this.children.push(module);
      module.parent = this;
    }
  }

  modules.main = new Module(window.location.href.split('?')[0])
  modules.main.filename = null;

  var fn = function(names) {
    var getOne = (name) => {
      var parent = this instanceof Module ? this : modules.main ;
      var url = join(parent.dirname, name + '.js');
      return new Promise(function(resolve, reject){
        var module = modules[url];
        if (module) {
          resolve(module.exports);
        } else {
          module = modules[url] = new Module(url);
          parent.addChildren(module);
          $.ajax(url, { cache: false, dataType: 'text'})
            .done(response => {
              new Function('module', response)(module);
              fn.bind(module)(module.require)
              .then(function(imports) {
                  module.prepare(imports);
                  delete module.prepare;
                  module.loaded = true;
                  resolve(module.exports);
              });
            })
            .fail(reject);
        }
      });
    };

    if (Array.isArray(names)) {
      return Promise.all(names.map(getOne));
    } else if (typeof names === 'string') {
      return getOne(names);
    } else {
      return new Promise((resolve, reject) => {resolve(names)});
    }
  }
  fn.modules = modules;
  return fn;
}({

}));
<commit_msg>Changed some criteria for resolving paths<commit_after>var require = (function() {
  // function copied from creationix/path.js
  function join(/* path segments */) {
    var parts = [];
    for (var i = 0, l = arguments.length; i < l; i++) {
      parts = parts.concat(arguments[i].split("/"));
    }
    var newParts = [];
    for (i = 0, l = parts.length; i < l; i++) {
      var part = parts[i];
      if (!part || part === ".") continue;
      if (part === "..") newParts.pop();
      else newParts.push(part);
    }
    if (parts[0] === "") newParts.unshift("");
    return newParts.join("/") || (newParts.length ? "/" : ".");
  }

  var modules = {};

  class Module {
    constructor(url) {
      this.loaded = false;

      this.filename = url;
      this.dirname = join(url, url.substr(-1) == '/' ? '.' : '..');

      this.children = [];
      this.require = [];
      this.prepare = imports => null,
      this.exports = {};
    }

    addChildren(module) {
      this.children.push(module);
      module.parent = this;
    }
  }
  modules.main = new Module(window.location.pathname);

  var fn = function(names) {
    var getOne = (name) => {
      var parent = this instanceof Module ? this : modules.main ;
      var with_js = name => name + (name.substr(-3) == '.js' ? '' : '.js');
      var url = join(parent.dirname, with_js(name));
      return new Promise(function(resolve, reject){
        var module = modules[url];
        if (module) {
          resolve(module.exports);
        } else {
          module = modules[url] = new Module(url);
          parent.addChildren(module);
          $.ajax(url, { cache: false, dataType: 'text'})
            .done(response => {
              new Function('module', response)(module);
              fn.bind(module)(module.require)
                .then(function(imports) {
                  module.prepare(imports);
                  delete module.prepare;
                  module.loaded = true;
                  resolve(module.exports);
                })
                .catch(reject);
            })
            .fail(reject);
        }
      });
    };

    if (Array.isArray(names)) {
      return Promise.all(names.map(getOne));
    } else if (typeof names === 'string') {
      return getOne(names);
    } else {
      return new Promise((resolve, reject) => {resolve(names)});
    }
  }
  fn.modules = modules;
  return fn;
}({

}));
<|endoftext|>