<commit_before>#!/usr/bin/env node
"use strict";

process.title = 'nswag';

console.log("NSwag NPM CLI");
var args = process.argv.splice(2, process.argv.length - 2).map(function(a) { return a.indexOf(" ") === -1 ? a : '"' + a + '"' }).join(" ");

// Search for full .NET installation
var hasFullDotNet = false;
var fs = require('fs');
if (process.env["windir"]) {
    try {
        var stats = fs.lstatSync(process.env["windir"] + '/Microsoft.NET');
        if (stats.isDirectory())
            hasFullDotNet = true;
    }
    catch (e) {
        console.log(e);
    }
}

var c = require('child_process');
if (hasFullDotNet && !args.endsWith("--core")) {
    // Run full .NET version
    var cmd = '"' + __dirname + '/binaries/full/nswag.exe" ' + args;
    var code = c.execSync(cmd, {stdio:[0,1,2]});
} else {
    // Run .NET Core version
    var cmd = "dotnet";
    var dotnetVersion = c.exec(cmd, (error, stdout, stderr) => {
        var dotnetVersion = stdout;
        if (dotnetVersion.indexOf("Version  : 1.0.0") !== -1)
            cmd = 'dotnet "' + __dirname + '/binaries/netcoreapp1.0/dotnet-nswag.dll" ' + args;
        else if (dotnetVersion.indexOf("Version  : 1.1.0") !== -1)
            cmd = 'dotnet "' + __dirname + '/binaries/netcoreapp1.1/dotnet-nswag.dll" ' + args;

        c.execSync(cmd, {stdio:[0,1,2]});
    });
}<commit_msg>Use .net core 1.1 as fallback, #769<commit_after>#!/usr/bin/env node
"use strict";

process.title = 'nswag';

console.log("NSwag NPM CLI");
var args = process.argv.splice(2, process.argv.length - 2).map(function(a) { return a.indexOf(" ") === -1 ? a : '"' + a + '"' }).join(" ");

// Search for full .NET installation
var hasFullDotNet = false;
var fs = require('fs');
if (process.env["windir"]) {
    try {
        var stats = fs.lstatSync(process.env["windir"] + '/Microsoft.NET');
        if (stats.isDirectory())
            hasFullDotNet = true;
    }
    catch (e) {
        console.log(e);
    }
}

var c = require('child_process');
if (hasFullDotNet && !args.endsWith("--core")) {
    // Run full .NET version
    var cmd = '"' + __dirname + '/binaries/full/nswag.exe" ' + args;
    var code = c.execSync(cmd, {stdio:[0,1,2]});
} else {
    // Run .NET Core version
    var cmd = "dotnet";
    var dotnetVersion = c.exec(cmd, (error, stdout, stderr) => {
        if (!error) {
            var dotnetVersion = stdout;
            if (dotnetVersion.indexOf("Version  : 1.0.0") !== -1)
                cmd = 'dotnet "' + __dirname + '/binaries/netcoreapp1.0/dotnet-nswag.dll" ' + args;
            else if (dotnetVersion.indexOf("Version  : 1.1.0") !== -1)
                cmd = 'dotnet "' + __dirname + '/binaries/netcoreapp1.1/dotnet-nswag.dll" ' + args;
        } else
            cmd = 'dotnet "' + __dirname + '/binaries/netcoreapp1.1/dotnet-nswag.dll" ' + args;

        c.execSync(cmd, {stdio:[0,1,2]});
    });
}<|endoftext|>


<commit_before>/* global exports */
/* global XMLHttpRequest */
/* global module */
"use strict";

// module Network.HTTP.Affjax

// jshint maxparams: 5
exports._ajax = function (mkHeader, options, canceler, errback, callback) {
  var platformSpecific = { };
  if (typeof module !== "undefined" && module.require) {
    // We are on node.js
    platformSpecific.newXHR = function () {
      var XHR = module.require("xhr2");
      return new XHR();
    };

    platformSpecific.fixupUrl = function (url) {
      var urllib = module.require("url");
      var u = urllib.parse(url);
      u.protocol = u.protocol || "http:";
      u.hostname = u.hostname || "localhost";
      return urllib.format(u);
    };

    platformSpecific.getResponse = function (xhr) {
      return xhr.response;
    };
  } else {
    // We are in the browser
    platformSpecific.newXHR = function () {
      return new XMLHttpRequest();
    };

    platformSpecific.fixupUrl = function (url) {
      return url || "/";
    };

    platformSpecific.getResponse = function (xhr) {
      return xhr.response;
    };
  }

  return function () {
    var xhr = platformSpecific.newXHR();
    var fixedUrl = platformSpecific.fixupUrl(options.url);
    xhr.open(options.method || "GET", fixedUrl, true, options.username, options.password);
    if (options.headers) {
      try {
        for (var i = 0, header; (header = options.headers[i]) != null; i++) {
          xhr.setRequestHeader(header.field, header.value);
        }
      }
      catch (e) {
        errback(e)();
      }
    }
    xhr.onerror = function () {
      errback(new Error("AJAX request failed: " + options.method + " " + options.url))();
    };
    xhr.onload = function () {
      callback({
        status: xhr.status,
        headers: xhr.getAllResponseHeaders().split("\r\n")
          .filter(function (header) {
            return header.length > 0;
          })
          .map(function (header) {
            var i = header.indexOf(":");
            return mkHeader(header.substring(0, i))(header.substring(i + 2));
          }),
        response: platformSpecific.getResponse(xhr)
      })();
    };
    xhr.responseType = options.responseType;
    xhr.withCredentials = options.withCredentials;
    xhr.send(options.content);
    return canceler(xhr);
  };
};

// jshint maxparams: 4
exports._cancelAjax = function (xhr, cancelError, errback, callback) {
  return function () {
    try { xhr.abort(); } catch (e) { return callback(false)(); }
    return callback(true)();
  };
};

<commit_msg>make it work for electron<commit_after>/* global exports */
/* global XMLHttpRequest */
/* global module */
/* global process */
"use strict";

// module Network.HTTP.Affjax

// jshint maxparams: 5
exports._ajax = function (mkHeader, options, canceler, errback, callback) {
  var platformSpecific = { };
  if (typeof module !== "undefined" && module.require && !(typeof process !== "undefined" && process.versions["electron"])) {
    // We are on node.js
    platformSpecific.newXHR = function () {
      var XHR = module.require("xhr2");
      return new XHR();
    };

    platformSpecific.fixupUrl = function (url) {
      var urllib = module.require("url");
      var u = urllib.parse(url);
      u.protocol = u.protocol || "http:";
      u.hostname = u.hostname || "localhost";
      return urllib.format(u);
    };

    platformSpecific.getResponse = function (xhr) {
      return xhr.response;
    };
  } else {
    // We are in the browser
    platformSpecific.newXHR = function () {
      return new XMLHttpRequest();
    };

    platformSpecific.fixupUrl = function (url) {
      return url || "/";
    };

    platformSpecific.getResponse = function (xhr) {
      return xhr.response;
    };
  }

  return function () {
    var xhr = platformSpecific.newXHR();
    var fixedUrl = platformSpecific.fixupUrl(options.url);
    xhr.open(options.method || "GET", fixedUrl, true, options.username, options.password);
    if (options.headers) {
      try {
        for (var i = 0, header; (header = options.headers[i]) != null; i++) {
          xhr.setRequestHeader(header.field, header.value);
        }
      }
      catch (e) {
        errback(e)();
      }
    }
    xhr.onerror = function () {
      errback(new Error("AJAX request failed: " + options.method + " " + options.url))();
    };
    xhr.onload = function () {
      callback({
        status: xhr.status,
        headers: xhr.getAllResponseHeaders().split("\r\n")
          .filter(function (header) {
            return header.length > 0;
          })
          .map(function (header) {
            var i = header.indexOf(":");
            return mkHeader(header.substring(0, i))(header.substring(i + 2));
          }),
        response: platformSpecific.getResponse(xhr)
      })();
    };
    xhr.responseType = options.responseType;
    xhr.withCredentials = options.withCredentials;
    xhr.send(options.content);
    return canceler(xhr);
  };
};

// jshint maxparams: 4
exports._cancelAjax = function (xhr, cancelError, errback, callback) {
  return function () {
    try { xhr.abort(); } catch (e) { return callback(false)(); }
    return callback(true)();
  };
};

<|endoftext|>


<commit_before>// app.shoppingListAddController.js

(function() {
  "use strict";

  angular.module("MyApp")
    .controller("ShoppingListAddController", ShoppingListAddController);

  ShoppingListAddController.$inject = ["ShoppingListService"];

  function ShoppingListAddController(ShoppingListService) {
    let AddCtrl = this;

    AddCtrl.itemName = "";
    AddCtrl.itemQuantity = 0;

    AddCtrl.addItem = addItem();

    function addItem() {
      ShoppingListService.addItem(AddCtrl.itemName, AddCtrl.itemQuantity);
    }
  }
})();
<commit_msg>Edit AddCtrl.itemQuantity, AddCtrl.addItem<commit_after>// app.shoppingListAddController.js

(function() {
  "use strict";

  angular.module("MyApp")
    .controller("ShoppingListAddController", ShoppingListAddController);

  ShoppingListAddController.$inject = ["ShoppingListService"];

  function ShoppingListAddController(ShoppingListService) {
    let AddCtrl = this;

    AddCtrl.itemName = "";
    AddCtrl.itemQuantity = "";

    AddCtrl.addItem = addItem;

    function addItem() {
      ShoppingListService.addItem(AddCtrl.itemName, AddCtrl.itemQuantity);

      AddCtrl.itemName = "";
      AddCtrl.itemQuantity = "";
    }
  }
})();
<|endoftext|>


<commit_before>(function() {

zeit.cms.declare_namespace('zeit.content.article');

var wire_forms = function() {
    forEach($$('#article-metadata .inline-form'), function(container) {
        //XXX need to make it context aware
        var url = container.getAttribute('action');
        var form = new zeit.cms.SubPageForm(
            url, container, {save_on_change: true});
    });
};

var ident = MochiKit.Signal.connect(
    zeit.edit.editor, 'script-loading-finished',
    function() {
        MochiKit.Signal.disconnect(ident);

    zeit.content.article.body_sorter = new zeit.edit.sortable.BlockSorter(
        'editable-body');
    wire_forms();
    });

// Initialize module library
MochiKit.Signal.connect(
    window, 'cp-editor-loaded', function() {
    zeit.edit.library.create(
        'article', context_url + '/editable-body', 'Artikel');
});

zeit.edit.drop.registerHandler({
    accept: ['editable-body-module'],
    activated_by: 'action-editable-body-module-droppable',
    url_attribute: 'cms:create-block-url',
    query_arguments: function(draggable) {
        return {'block_type': draggable.getAttribute('cms:block_type')};
    }
});

zeit.content.article.Editable = gocept.Class.extend({
    // Inline editing module

    editor_active_lock: new MochiKit.Async.DeferredLock(),

    construct: function(context_element, place_cursor_at_end) {
        var self = this;
        var block_id = MochiKit.DOM.getFirstParentByTagAndClassName(
            context_element, null, 'block').id;
        var d = self.editor_active_lock.acquire()
        log('Waiting for lock');
        d.addCallback(function() {
            var block = $(block_id)
            if (block === null) {
                // block vanished while waiting for lock.
                return
            }
            self.events = [];
            self.edited_paragraphs = [];
            self.initial_paragraph = MochiKit.Selector.findChildElements(
                block, ['.editable > *'])[0];
            self.editable = self.merge(block);
            self.block = MochiKit.DOM.getFirstParentByTagAndClassName(
                self.editable, null, 'block');
            log('Editable block', self.block.id);
            self.editable.removeAttribute('cms:cp-module');
            self.editable.contentEditable = true;
            self.editable.focus();
            self.command('styleWithCSS', false);
            self.init_toolbar();
            MochiKit.DOM.addElementClass(self.block, 'editing');

            // This catches the blur-signal in the capturing-phase!
            // In case you use the toolbar, the editing-mode won't be stopped.
            self.editable.parentNode.addEventListener("blur", function(e) {
                var clicked_on_block =
                    MochiKit.DOM.getFirstParentByTagAndClassName(
                       e.explicitOriginalTarget, 'div', 'block');
                is_in_block = (clicked_on_block == self.block);
                log("Blur while editing:", is_in_block);
                if (is_in_block) {
                    e.stopPropagation();
                } else {
                    self.save();
                }
            }, true);
            self.events.push(MochiKit.Signal.connect(
                self.editable, 'onkeydown', self, self.handle_keydown));
            self.place_cursor(self.initial_paragraph, place_cursor_at_end);
        });
    },

    place_cursor: function(element, place_cursor_at_end) {
        // Place cursor to the beginnning of element
        log('Placing cursor to', element.nodeName);
        var range = getSelection().getRangeAt(0);
        var direction;
        if (place_cursor_at_end)  {
            direction = 'lastChild';
        } else {
            direction = 'firstChild';
        }

        var text_node = element;
        while (text_node[direction] !== null) {
            text_node = text_node[direction];
        };
        var select_node = text_node.parentNode;
        var offset = 0;
        if (place_cursor_at_end)  {
            offset = text_node.data.length;
        }
        range.setStart(text_node, offset);
        range.setEnd(text_node, offset);
    },

    is_block_editable: function(block) {
        return !isNull(
            MochiKit.DOM.getFirstElementByTagAndClassName(
                'div', 'editable', block));
    },

    merge: function(block) {
        var self = this;
        var blocks = MochiKit.DOM.getElementsByTagAndClassName(
            null, 'block', block.parentNode);
        var i = blocks.indexOf(block);
        var paragraphs = [];
        // XXX remove code duplication
        while (i > 0) {
            i -= 1;
            if (self.is_block_editable(blocks[i])) {
                paragraphs.push(blocks[i]);
            } else {
                break;
            }
        }
        paragraphs.reverse();
        paragraphs.push(block);
        i = blocks.indexOf(block);
        while (i < blocks.length-1) {
            i += 1;
            if (self.is_block_editable(blocks[i])) {
                paragraphs.push(blocks[i]);
            } else {
                break;
            }
        }
        self.edited_paragraphs = MochiKit.Base.map(
            function(element) { return element.id; },
            paragraphs);
        var editable = MochiKit.DOM.getFirstElementByTagAndClassName(
            null, 'editable', paragraphs[0]);
        forEach(paragraphs.slice(1), function(paragraph) {
            forEach(MochiKit.Selector.findChildElements(
                paragraph, ['.editable > *']), function(p) {
                editable.appendChild(p);
            });
            MochiKit.DOM.removeElement(paragraph);
        });
        // Clear out all non element nodes
        forEach(editable.childNodes, function(child) {
            if (child.nodeType != child.ELEMENT_NODE) {
                editable.removeChild(child);
            }
        });
        return editable;
    },

    init_toolbar: function() {
        var self = this;
        self.toolbar = self.editable.parentNode.insertBefore(
            DIV({'class': 'rte-toolbar', 'style': 'display: block'}),
            self.editable);
        self.toolbar.innerHTML = "\
            B\
            I\
            UL\
            OL\
            T\
            p\
            a\
            save\
            ";
        self.events.push(MochiKit.Signal.connect(
            self.toolbar, 'onclick',
            self, self.handle_toolbar_click))
    },

    handle_toolbar_click: function(event) {
        log('Toolbar click');
        var self = this;
        if (event.target().nodeName != 'A') {
            return;
        }
        event.stop()
        if (event.target().rel == 'command') {
            event.stop();
            var action = event.target().getAttribute('href').split('/');
            self.command(action[0], action[1]);
        } else if (event.target().rel == 'method') {
            var method = event.target().getAttribute('href');
            self[method]();
        }
    },

    handle_keydown: function(event) {
        var self = this;

        var range = getSelection().getRangeAt(0);
        var container = range.commonAncestorContainer;
        // lastnode/firstnodee?
        var direction = null;
        var cursor_at_end = false;
        if (event.key().string == 'KEY_ARROW_DOWN' &&
            container.nodeType == container.TEXT_NODE &&  // Last
            container.parentNode.nextSibling === null &&  // node
            MochiKit.DOM.scrapeText(container).length == range.endOffset) {
            direction = 'nextSibling';
        } else if (
            event.key().string == 'KEY_ARROW_UP' &&
            container.nodeType == container.TEXT_NODE &&      // First
            container.parentNode.previousSibling === null &&  // node
            range.startOffset == 0) {
            direction = 'previousSibling';
            cursor_at_end = true;
        }
        if (direction !== null) {
            var blocks = MochiKit.Selector.findChildElements(
                self.block.parentNode, ['.block']);
            var block = self.block;
            var next_block = null;
            while (block[direction] !== null) {
                block = block[direction];
                if (block.nodeType != block.ELEMENT_NODE) {
                    continue
                }
                if (MochiKit.DOM.hasElementClass(block, 'block') &&
                    self.is_block_editable(block)) {
                    next_block = block;
                    break
                }
            }
            if (next_block !== null) {
                log('Next block', next_block.id);
                // Note id as save may (or probably will) replace the element
                var next_block_id = next_block.id;
                self.save();
                new zeit.content.article.Editable(
                    MochiKit.DOM.getFirstElementByTagAndClassName(
                        'div', 'editable', $(next_block_id)),
                    cursor_at_end);
                event.stop();
            }

        }
    },

    get_text_list: function() {
        var self = this;
        var result = []
        forEach(self.editable.childNodes, function(element) {
            if (element.nodeType == element.ELEMENT_NODE) {
                result.push({factory: element.nodeName.toLowerCase(),
                             text: element.innerHTML});
            }
        });
        return result;
    },

    save: function() {
        var self = this;
        log('Saving');
        MochiKit.DOM.addElementClass(self.block, 'busy');
        while (self.events.length) {
            MochiKit.Signal.disconnect(self.events.pop());
        }
        // until now, the editor can only be contained in an editable-body.
        var url = $('editable-body').getAttribute('cms:url') + '/@@save_text';
        zeit.edit.makeJSONRequest(url, {
            paragraphs: self.edited_paragraphs,
            text: self.get_text_list()});
        var ident = MochiKit.Signal.connect(
            zeit.edit.editor, 'after-reload', function() {
            MochiKit.Signal.disconnect(ident);
            self.editor_active_lock.release();
        });
    },

    command: function(command, option) {
        var self = this;
        log("Executing", command, option);
        try {
            document.execCommand(command, false, option);
        } catch(e) {
			window.console && console.log(e)
		}
		//this._updateToolbar();
    }

});

})();
<commit_msg>coding style: fix JS ambiguities and add semikolons<commit_after>(function() {

zeit.cms.declare_namespace('zeit.content.article');

var wire_forms = function() {
    forEach($$('#article-metadata .inline-form'), function(container) {
        //XXX need to make it context aware
        var url = container.getAttribute('action');
        var form = new zeit.cms.SubPageForm(
            url, container, {save_on_change: true});
    });
};

var ident = MochiKit.Signal.connect(
    zeit.edit.editor, 'script-loading-finished',
    function() {
        MochiKit.Signal.disconnect(ident);

    zeit.content.article.body_sorter = new zeit.edit.sortable.BlockSorter(
        'editable-body');
    wire_forms();
    });

// Initialize module library
MochiKit.Signal.connect(
    window, 'cp-editor-loaded', function() {
    zeit.edit.library.create(
        'article', context_url + '/editable-body', 'Artikel');
});

zeit.edit.drop.registerHandler({
    accept: ['editable-body-module'],
    activated_by: 'action-editable-body-module-droppable',
    url_attribute: 'cms:create-block-url',
    query_arguments: function(draggable) {
        return {'block_type': draggable.getAttribute('cms:block_type')};
    }
});

zeit.content.article.Editable = gocept.Class.extend({
    // Inline editing module

    editor_active_lock: new MochiKit.Async.DeferredLock(),

    construct: function(context_element, place_cursor_at_end) {
        var self = this;
        var block_id = MochiKit.DOM.getFirstParentByTagAndClassName(
            context_element, null, 'block').id;
        var d = self.editor_active_lock.acquire();
        log('Waiting for lock');
        d.addCallback(function() {
            var block = $(block_id);
            if (block === null) {
                // block vanished while waiting for lock.
                return;
            }
            self.events = [];
            self.edited_paragraphs = [];
            self.initial_paragraph = MochiKit.Selector.findChildElements(
                block, ['.editable > *'])[0];
            self.editable = self.merge(block);
            self.block = MochiKit.DOM.getFirstParentByTagAndClassName(
                self.editable, null, 'block');
            log('Editable block', self.block.id);
            self.editable.removeAttribute('cms:cp-module');
            self.editable.contentEditable = true;
            self.editable.focus();
            self.command('styleWithCSS', false);
            self.init_toolbar();
            MochiKit.DOM.addElementClass(self.block, 'editing');

            // This catches the blur-signal in the capturing-phase!
            // In case you use the toolbar, the editing-mode won't be stopped.
            self.editable.parentNode.addEventListener("blur", function(e) {
                var clicked_on_block =
                    MochiKit.DOM.getFirstParentByTagAndClassName(
                       e.explicitOriginalTarget, 'div', 'block');
                is_in_block = (clicked_on_block == self.block);
                log("Blur while editing:", is_in_block);
                if (is_in_block) {
                    e.stopPropagation();
                } else {
                    self.save();
                }
            }, true);
            self.events.push(MochiKit.Signal.connect(
                self.editable, 'onkeydown', self, self.handle_keydown));
            self.place_cursor(self.initial_paragraph, place_cursor_at_end);
        });
    },

    place_cursor: function(element, place_cursor_at_end) {
        // Place cursor to the beginnning of element
        log('Placing cursor to', element.nodeName);
        var range = getSelection().getRangeAt(0);
        var direction;
        if (place_cursor_at_end)  {
            direction = 'lastChild';
        } else {
            direction = 'firstChild';
        }

        var text_node = element;
        while (text_node[direction] !== null) {
            text_node = text_node[direction];
        }
        var select_node = text_node.parentNode;
        var offset = 0;
        if (place_cursor_at_end)  {
            offset = text_node.data.length;
        }
        range.setStart(text_node, offset);
        range.setEnd(text_node, offset);
    },

    is_block_editable: function(block) {
        return !isNull(
            MochiKit.DOM.getFirstElementByTagAndClassName(
                'div', 'editable', block));
    },

    merge: function(block) {
        var self = this;
        var blocks = MochiKit.DOM.getElementsByTagAndClassName(
            null, 'block', block.parentNode);
        var i = blocks.indexOf(block);
        var paragraphs = [];
        // XXX remove code duplication
        while (i > 0) {
            i -= 1;
            if (self.is_block_editable(blocks[i])) {
                paragraphs.push(blocks[i]);
            } else {
                break;
            }
        }
        paragraphs.reverse();
        paragraphs.push(block);
        i = blocks.indexOf(block);
        while (i < blocks.length-1) {
            i += 1;
            if (self.is_block_editable(blocks[i])) {
                paragraphs.push(blocks[i]);
            } else {
                break;
            }
        }
        self.edited_paragraphs = MochiKit.Base.map(
            function(element) { return element.id; },
            paragraphs);
        var editable = MochiKit.DOM.getFirstElementByTagAndClassName(
            null, 'editable', paragraphs[0]);
        forEach(paragraphs.slice(1), function(paragraph) {
            forEach(MochiKit.Selector.findChildElements(
                paragraph, ['.editable > *']), function(p) {
                editable.appendChild(p);
            });
            MochiKit.DOM.removeElement(paragraph);
        });
        // Clear out all non element nodes
        forEach(editable.childNodes, function(child) {
            if (child.nodeType != child.ELEMENT_NODE) {
                editable.removeChild(child);
            }
        });
        return editable;
    },

    init_toolbar: function() {
        var self = this;
        self.toolbar = self.editable.parentNode.insertBefore(
            DIV({'class': 'rte-toolbar', 'style': 'display: block'}),
            self.editable);
        self.toolbar.innerHTML = "\
            B\
            I\
            UL\
            OL\
            T\
            p\
            a\
            save\
            ";
        self.events.push(MochiKit.Signal.connect(
            self.toolbar, 'onclick',
            self, self.handle_toolbar_click));
    },

    handle_toolbar_click: function(event) {
        log('Toolbar click');
        var self = this;
        if (event.target().nodeName != 'A') {
            return;
        }
        event.stop();
        if (event.target().rel == 'command') {
            event.stop();
            var action = event.target().getAttribute('href').split('/');
            self.command(action[0], action[1]);
        } else if (event.target().rel == 'method') {
            var method = event.target().getAttribute('href');
            self[method]();
        }
    },

    handle_keydown: function(event) {
        var self = this;

        var range = getSelection().getRangeAt(0);
        var container = range.commonAncestorContainer;
        // lastnode/firstnodee?
        var direction = null;
        var cursor_at_end = false;
        if (event.key().string == 'KEY_ARROW_DOWN' &&
            container.nodeType == container.TEXT_NODE &&  // Last
            container.parentNode.nextSibling === null &&  // node
            MochiKit.DOM.scrapeText(container).length == range.endOffset) {
            direction = 'nextSibling';
        } else if (
            event.key().string == 'KEY_ARROW_UP' &&
            container.nodeType == container.TEXT_NODE &&      // First
            container.parentNode.previousSibling === null &&  // node
            range.startOffset === 0) {
            direction = 'previousSibling';
            cursor_at_end = true;
        }
        if (direction !== null) {
            var blocks = MochiKit.Selector.findChildElements(
                self.block.parentNode, ['.block']);
            var block = self.block;
            var next_block = null;
            while (block[direction] !== null) {
                block = block[direction];
                if (block.nodeType != block.ELEMENT_NODE) {
                    continue;
                }
                if (MochiKit.DOM.hasElementClass(block, 'block') &&
                    self.is_block_editable(block)) {
                    next_block = block;
                    break;
                }
            }
            if (next_block !== null) {
                log('Next block', next_block.id);
                // Note id as save may (or probably will) replace the element
                var next_block_id = next_block.id;
                self.save();
                new zeit.content.article.Editable(
                    MochiKit.DOM.getFirstElementByTagAndClassName(
                        'div', 'editable', $(next_block_id)),
                    cursor_at_end);
                event.stop();
            }

        }
    },

    get_text_list: function() {
        var self = this;
        var result = [];
        forEach(self.editable.childNodes, function(element) {
            if (element.nodeType == element.ELEMENT_NODE) {
                result.push({factory: element.nodeName.toLowerCase(),
                             text: element.innerHTML});
            }
        });
        return result;
    },

    save: function() {
        var self = this;
        log('Saving');
        MochiKit.DOM.addElementClass(self.block, 'busy');
        while (self.events.length) {
            MochiKit.Signal.disconnect(self.events.pop());
        }
        // until now, the editor can only be contained in an editable-body.
        var url = $('editable-body').getAttribute('cms:url') + '/@@save_text';
        zeit.edit.makeJSONRequest(url, {
            paragraphs: self.edited_paragraphs,
            text: self.get_text_list()});
        var ident = MochiKit.Signal.connect(
            zeit.edit.editor, 'after-reload', function() {
            MochiKit.Signal.disconnect(ident);
            self.editor_active_lock.release();
        });
    },

    command: function(command, option) {
        var self = this;
        log("Executing", command, option);
        try {
            document.execCommand(command, false, option);
        } catch(e) {
            window.console && console.log(e);
		}
		//this._updateToolbar();
    }

});

})();
<|endoftext|>


<commit_before>import './Menu.js';
import { indexOfItemContainingTarget, elementsFromPoint, ownEvent } from './utilities.js';
import { merge } from './updates.js';
import * as symbols from './symbols.js';
import PopupSource from './PopupSource.js';

const menuTagKey = Symbol('menuTag');
const documentMouseupListenerKey = Symbol('documentMouseupListener');

/**
 * A button that invokes a menu.
 *
 * @inherits PopupSource
 * @elementtag {Menu} menu
 */
class MenuButton extends PopupSource {

  componentDidMount() {
    if (super.componentDidMount) { super.componentDidMount(); }

    // If we're doing a drag-select, and the user hovers over an item, select
    // it.
    this.addEventListener('mousemove', event => {
      const target = event.target;
      if (target && this.state.dragSelect) {
        /** @type {any} */
        const cast = target;
        const hoverIndex = indexOfItemContainingTarget(this, cast);
        if (hoverIndex !== this.state.menuSelectedIndex) {
          this[symbols.raiseChangeEvents] = true;
          this.setState({
            menuSelectedIndex: hoverIndex
          });
          this[symbols.raiseChangeEvents] = false;
        }
      }
    });

    // If the popup is open and user releases the mouse over the backdrop, close
    // the popup. We need to listen to mouseup on the document, not this
    // element. If the user mouses down on the source, then moves the mouse off
    // the document before releasing the mouse, the element itself won't get the
    // mouseup. The document will, however, so it's a more reliable source of
    // mouse state.
    //
    // Coincidentally, we *also* need to listen to mouseup on the document to
    // tell whether the user released the mouse over the source button. When the
    // user mouses down, the backdrop will appear and cover the source, so from
    // that point on the source won't receive a mouseup event. Again, we can
    // listen to mouseup on the document and do our own hit-testing to see if
    // the user released the mouse over the source.
    this[documentMouseupListenerKey] = async (event) => {
      const hitTargets = elementsFromPoint(this, event.clientX, event.clientY);
      const overSource = hitTargets.indexOf(this.$.source) >= 0;
      if (this.opened) {
        if (overSource) {
          // User released the mouse over the source button (behind the
          // backdrop), so we're no longer doing a drag-select.
          if (this.state.dragSelect) {
            this[symbols.raiseChangeEvents] = true;
            this.setState({
              dragSelect: false
            });
            this[symbols.raiseChangeEvents] = false;
          }
        } else {
          // If we get to this point, the user released over the backdrop with
          // the popup open, so close.
          this[symbols.raiseChangeEvents] = true;
          await this.close();
          this[symbols.raiseChangeEvents] = false;
        }
      }
    };

    if (this.state.opened) {
      addDocumentListeners(this);
    }

    // Close the popup if menu loses focus.
    this.$.menu.addEventListener('blur', async (event) => {
      if (!ownEvent(this, event) && this.opened) {
        this[symbols.raiseChangeEvents] = true;
        await this.close();
        this[symbols.raiseChangeEvents] = false;
      }
    });

    // mousedown events on the menu will propagate up to the top-level element,
    // which will then steal the focus. We want to keep the focus on the menu,
    // both to permit keyboard use, and to avoid closing the menu on blur (see
    // separate blur handler). To keep the focus on the menu, we prevent the
    // default event behavior.
    this.$.menu.addEventListener('mousedown', event => {
      if (this.opened) {
        event.stopPropagation();
        event.preventDefault();
      }
    });

    // If the user mouses up on a menu item, close the menu with that item as
    // the close result.
    const mouseupHandler = async (event) => {
      // If we're doing a drag-select (user moused down on button, dragged
      // mouse into menu, and released), we close. If we're not doing a
      // drag-select (the user opened the menu with a complete click), and
      // there's a selection, they clicked on an item, so also close.
      // Otherwise, the user clicked the menu open, then clicked on a menu
      // separator or menu padding; stay open.
      const menuSelectedIndex = this.state.menuSelectedIndex;
      if (this.state.dragSelect || menuSelectedIndex >= 0) {
        const closeResult = menuSelectedIndex >= 0 ?
          menuSelectedIndex :
          undefined;
        this[symbols.raiseChangeEvents] = true;
        await this.close(closeResult);
        this[symbols.raiseChangeEvents] = false;
      } else {
        event.stopPropagation();
      }
    }
    this.$.menu.addEventListener('mouseup', mouseupHandler);

    this.$.menu.addEventListener('touchstart', event => {
      const touch = event.changedTouches[0];
      this.setState({
        touchstartX: touch.clientX,
        touchstartY: touch.clientY
      });
    });

    // Listen to touchend for fast-tap response on Safari. (Chrome has better
    // touch/mouse heuristics, so doesn't need this, but it doesn't hurt.)
    this.$.menu.addEventListener('touchend', event => {
      const touch = event.changedTouches[0];
      const { touchstartX, touchstartY } = this.state;
      // A null touchstartX or touchstartY will be treated as 0.
      const deltaX = Math.abs(touch.clientX - touchstartX);
      const deltaY = Math.abs(touch.clientY - touchstartY);
      const dragThreshold = 2; // pixels
      const userDragged = deltaX > dragThreshold || deltaY > dragThreshold;
      if (!userDragged) {
        // User didn't drag; treat the tap as a (faster) mouseup.
        return mouseupHandler(event);
      }
    });

    // Track changes in the menu's selection state.
    this.$.menu.addEventListener('selected-index-changed', event => {
      /** @type {any} */
      const cast = event;
      this.setState({
        menuSelectedIndex: cast.detail.selectedIndex
      });
    });

    // When OverlayMixin opens the popup, we want it to focus on the first menu
    // item.
    this.$.popup[symbols.defaultFocus] = this.$.menu;
  }

  componentDidUpdate(previousState) {
    if (super.componentDidUpdate) { super.componentDidUpdate(previousState); }

    if (this.state.opened !== previousState.opened) {
      if (this.state.opened) {
        addDocumentListeners(this);
      } else {
        removeDocumentListeners(this);
      }

      if (this[symbols.raiseChangeEvents] && this.state.selectedItem) {
        this.itemSelected(this.state.selectedItem);
      }
    }
  }

  // The index that will be selected by default when the menu opens.
  get defaultMenuSelectedIndex() {
    return -1;
  }

  get defaults() {
    const base = super.defaults || {};
    return Object.assign({}, base, {
      tags: Object.assign({}, base.tags, {
        menu: 'elix-menu'
      })
    });
  }

  get defaultState() {
    return Object.assign({}, super.defaultState, {
      dragSelect: true,
      menuSelectedIndex: -1,
      selectedItem: null,
      touchstartX: null,
      touchstartY: null
    });
  }

  disconnectedCallback() {
    //@ts-ignore
    if (super.disconnectedCallback) { super.disconnectedCallback(); }
    document.removeEventListener('mouseup', this[documentMouseupListenerKey]);
    this[documentMouseupListenerKey] = null;
  }

  get items() {
    /** @type {any} */
    const menu = this.$ && this.$.menu;
    return menu ? menu.items : null;
  }

  itemSelected(item) {
    /**
     * Raised when the user selects a menu item.
     *
     * @event MenuButton#menu-item-selected
     */
    const event = new CustomEvent('menu-item-selected', {
      detail: {
        selectedItem: item
      }
    });
    this.dispatchEvent(event);
  }

  [symbols.keydown](event) {

    switch (event.key) {
      // When open, Enter closes popup.
      case 'Enter':
        if (this.opened) {
          this.close(this.state.menuSelectedIndex);
          return true;
        }
    }

    // Give superclass a chance to handle.
    const base = super[symbols.keydown] && super[symbols.keydown](event);
    if (base) {
      return true;
    }

    if (this.opened && !event.metaKey && !event.altKey) {
      // If they haven't already been handled, absorb keys that might cause the
      // page to scroll in the background, which would in turn cause the popup to
      // inadvertently close.
      switch (event.key) {
        case 'ArrowDown':
        case 'ArrowLeft':
        case 'ArrowRight':
        case 'ArrowUp':
        case 'End':
        case 'Home':
        case 'PageDown':
        case 'PageUp':
        case ' ':
          return true;
      }
    }

    return false;
  }

  /**
   * The tag used to define the menu.
   *
   * The menu element is responsible for presenting the menu items and handling
   * navigation between them.
   *
   * @type {string}
   * @default 'elix-menu'
   */
  get menuTag() {
    return this[menuTagKey];
  }
  set menuTag(menuTag) {
    this[symbols.hasDynamicTemplate] = true;
    this[menuTagKey] = menuTag;
  }

  get popupTemplate() {
    const base = super.popupTemplate;
    const menuTag = this.menuTag || this.defaults.tags.menu;
    const template = base.replace('<slot></slot>', `
      <${menuTag} id="menu">
        <slot></slot>
      </${menuTag}>
    `);
    return template;
  }

  refineState(state) {
    let result = super.refineState ? super.refineState(state) : true;
    if (state.opened && !this.opened) {
      // Opening
      if (!state.dragSelect) {
        // Until we get a mouseup, we're doing a drag-select.
        state.dragSelect = true;
        result = false;
      }
      if (state.selectedItem) {
        // Clear any previously selected item.
        state.selectedItem = null;
        result = false;
      }
      if (state.touchstartX !== null || state.touchstartY) {
        // Clear previous touchstart point.
        state.touchstartX = null;
        state.touchstartY = null;
        result = false;
      }
      // Select the default item in the menu.
      const defaultMenuSelectedIndex = this.defaultMenuSelectedIndex;
      if (state.menuSelectedIndex !== defaultMenuSelectedIndex) {
        state.menuSelectedIndex = defaultMenuSelectedIndex;
        result = false;
      }
    } else if (!state.opened && this.opened) {
      // Closing
      if (state.menuSelectedIndex !== -1) {
        // Clear menu selection.
        state.menuSelectedIndex = -1;
        result = false;
      }
    }
    return result;
  }

  get sourceSlotContent() {
    // Default "..." icon from Google Material Design icons.
    return `
      <svg id="ellipsisIcon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
        <path d="M6 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm12 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-6 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/>
      </svg>
    `;
  }

  get updates() {
    const base = super.updates;
    return merge(base, {
      $: {
        menu: {
          style: {
            background: 'window',
            border: 'none',
            'max-height': '100%',
            padding: '0.5em 0'
          },
          selectedIndex: this.state.menuSelectedIndex
        },
        popup: {
          attributes: {
            tabindex: null
          }
        },
        source: {
          style: {
            'align-items': 'center',
            display: 'flex'
          }
        }
      }
    },
    this.$.ellipsisIcon && {
      $: {
        ellipsisIcon: {
          style: {
            display: 'block',
            fill: 'currentColor'
          }
        }
      }
    });
  }

}

function addDocumentListeners(element) {
  document.addEventListener('mouseup', element[documentMouseupListenerKey]);
}

function removeDocumentListeners(element) {
  document.removeEventListener('mouseup', element[documentMouseupListenerKey]);
}

export default MenuButton;
customElements.define('elix-menu-button', MenuButton);
<commit_msg>Comments<commit_after>import './Menu.js';
import { indexOfItemContainingTarget, elementsFromPoint, ownEvent } from './utilities.js';
import { merge } from './updates.js';
import * as symbols from './symbols.js';
import PopupSource from './PopupSource.js';

const menuTagKey = Symbol('menuTag');
const documentMouseupListenerKey = Symbol('documentMouseupListener');

/**
 * A button that invokes a menu.
 *
 * @inherits PopupSource
 * @elementtag {Menu} menu
 */
class MenuButton extends PopupSource {

  componentDidMount() {
    if (super.componentDidMount) { super.componentDidMount(); }

    // If we're doing a drag-select, and the user hovers over an item, select
    // it.
    this.addEventListener('mousemove', event => {
      const target = event.target;
      if (target && this.state.dragSelect) {
        /** @type {any} */
        const cast = target;
        const hoverIndex = indexOfItemContainingTarget(this, cast);
        if (hoverIndex !== this.state.menuSelectedIndex) {
          this[symbols.raiseChangeEvents] = true;
          this.setState({
            menuSelectedIndex: hoverIndex
          });
          this[symbols.raiseChangeEvents] = false;
        }
      }
    });

    // If the popup is open and user releases the mouse over the backdrop, close
    // the popup. We need to listen to mouseup on the document, not this
    // element. If the user mouses down on the source, then moves the mouse off
    // the document before releasing the mouse, the element itself won't get the
    // mouseup. The document will, however, so it's a more reliable source of
    // mouse state.
    //
    // Coincidentally, we *also* need to listen to mouseup on the document to
    // tell whether the user released the mouse over the source button. When the
    // user mouses down, the backdrop will appear and cover the source, so from
    // that point on the source won't receive a mouseup event. Again, we can
    // listen to mouseup on the document and do our own hit-testing to see if
    // the user released the mouse over the source.
    this[documentMouseupListenerKey] = async (event) => {
      const hitTargets = elementsFromPoint(this, event.clientX, event.clientY);
      const overSource = hitTargets.indexOf(this.$.source) >= 0;
      if (this.opened) {
        if (overSource) {
          // User released the mouse over the source button (behind the
          // backdrop), so we're no longer doing a drag-select.
          if (this.state.dragSelect) {
            this[symbols.raiseChangeEvents] = true;
            this.setState({
              dragSelect: false
            });
            this[symbols.raiseChangeEvents] = false;
          }
        } else {
          // If we get to this point, the user released over the backdrop with
          // the popup open, so close.
          this[symbols.raiseChangeEvents] = true;
          await this.close();
          this[symbols.raiseChangeEvents] = false;
        }
      }
    };

    if (this.state.opened) {
      addDocumentListeners(this);
    }

    // Close the popup if menu loses focus.
    this.$.menu.addEventListener('blur', async (event) => {
      if (!ownEvent(this, event) && this.opened) {
        this[symbols.raiseChangeEvents] = true;
        await this.close();
        this[symbols.raiseChangeEvents] = false;
      }
    });

    // mousedown events on the menu will propagate up to the top-level element,
    // which will then steal the focus. We want to keep the focus on the menu,
    // both to permit keyboard use, and to avoid closing the menu on blur (see
    // separate blur handler). To keep the focus on the menu, we prevent the
    // default event behavior.
    this.$.menu.addEventListener('mousedown', event => {
      if (this.opened) {
        event.stopPropagation();
        event.preventDefault();
      }
    });

    // If the user mouses up on a menu item, close the menu with that item as
    // the close result.
    const mouseupHandler = async (event) => {
      // If we're doing a drag-select (user moused down on button, dragged
      // mouse into menu, and released), we close. If we're not doing a
      // drag-select (the user opened the menu with a complete click), and
      // there's a selection, they clicked on an item, so also close.
      // Otherwise, the user clicked the menu open, then clicked on a menu
      // separator or menu padding; stay open.
      const menuSelectedIndex = this.state.menuSelectedIndex;
      if (this.state.dragSelect || menuSelectedIndex >= 0) {
        const closeResult = menuSelectedIndex >= 0 ?
          menuSelectedIndex :
          undefined;
        this[symbols.raiseChangeEvents] = true;
        await this.close(closeResult);
        this[symbols.raiseChangeEvents] = false;
      } else {
        event.stopPropagation();
      }
    }
    this.$.menu.addEventListener('mouseup', mouseupHandler);

    this.$.menu.addEventListener('touchstart', event => {
      // Record the touch start location so we can later distinguish a fast tap
      // from a scroll or drag.
      const touch = event.changedTouches[0];
      this.setState({
        touchstartX: touch.clientX,
        touchstartY: touch.clientY
      });
    });

    // Listen to touchend for fast-tap response on Safari. (Chrome has better
    // touch/mouse heuristics, so doesn't need this, but it doesn't hurt.)
    this.$.menu.addEventListener('touchend', event => {
      const touch = event.changedTouches[0];
      const { touchstartX, touchstartY } = this.state;
      // A null touchstartX or touchstartY will be treated as 0.
      const deltaX = Math.abs(touch.clientX - touchstartX);
      const deltaY = Math.abs(touch.clientY - touchstartY);
      const dragThreshold = 2; // pixels
      const userDragged = deltaX > dragThreshold || deltaY > dragThreshold;
      if (!userDragged) {
        // User didn't drag; treat the tap as a (faster) mouseup.
        return mouseupHandler(event);
      }
    });

    // Track changes in the menu's selection state.
    this.$.menu.addEventListener('selected-index-changed', event => {
      /** @type {any} */
      const cast = event;
      this.setState({
        menuSelectedIndex: cast.detail.selectedIndex
      });
    });

    // When OverlayMixin opens the popup, we want it to focus on the first menu
    // item.
    this.$.popup[symbols.defaultFocus] = this.$.menu;
  }

  componentDidUpdate(previousState) {
    if (super.componentDidUpdate) { super.componentDidUpdate(previousState); }

    if (this.state.opened !== previousState.opened) {
      if (this.state.opened) {
        addDocumentListeners(this);
      } else {
        removeDocumentListeners(this);
      }

      if (this[symbols.raiseChangeEvents] && this.state.selectedItem) {
        this.itemSelected(this.state.selectedItem);
      }
    }
  }

  // The index that will be selected by default when the menu opens.
  get defaultMenuSelectedIndex() {
    return -1;
  }

  get defaults() {
    const base = super.defaults || {};
    return Object.assign({}, base, {
      tags: Object.assign({}, base.tags, {
        menu: 'elix-menu'
      })
    });
  }

  get defaultState() {
    return Object.assign({}, super.defaultState, {
      dragSelect: true,
      menuSelectedIndex: -1,
      selectedItem: null,
      touchstartX: null,
      touchstartY: null
    });
  }

  disconnectedCallback() {
    //@ts-ignore
    if (super.disconnectedCallback) { super.disconnectedCallback(); }
    document.removeEventListener('mouseup', this[documentMouseupListenerKey]);
    this[documentMouseupListenerKey] = null;
  }

  get items() {
    /** @type {any} */
    const menu = this.$ && this.$.menu;
    return menu ? menu.items : null;
  }

  itemSelected(item) {
    /**
     * Raised when the user selects a menu item.
     *
     * @event MenuButton#menu-item-selected
     */
    const event = new CustomEvent('menu-item-selected', {
      detail: {
        selectedItem: item
      }
    });
    this.dispatchEvent(event);
  }

  [symbols.keydown](event) {

    switch (event.key) {
      // When open, Enter closes popup.
      case 'Enter':
        if (this.opened) {
          this.close(this.state.menuSelectedIndex);
          return true;
        }
    }

    // Give superclass a chance to handle.
    const base = super[symbols.keydown] && super[symbols.keydown](event);
    if (base) {
      return true;
    }

    if (this.opened && !event.metaKey && !event.altKey) {
      // If they haven't already been handled, absorb keys that might cause the
      // page to scroll in the background, which would in turn cause the popup to
      // inadvertently close.
      switch (event.key) {
        case 'ArrowDown':
        case 'ArrowLeft':
        case 'ArrowRight':
        case 'ArrowUp':
        case 'End':
        case 'Home':
        case 'PageDown':
        case 'PageUp':
        case ' ':
          return true;
      }
    }

    return false;
  }

  /**
   * The tag used to define the menu.
   *
   * The menu element is responsible for presenting the menu items and handling
   * navigation between them.
   *
   * @type {string}
   * @default 'elix-menu'
   */
  get menuTag() {
    return this[menuTagKey];
  }
  set menuTag(menuTag) {
    this[symbols.hasDynamicTemplate] = true;
    this[menuTagKey] = menuTag;
  }

  get popupTemplate() {
    const base = super.popupTemplate;
    const menuTag = this.menuTag || this.defaults.tags.menu;
    const template = base.replace('<slot></slot>', `
      <${menuTag} id="menu">
        <slot></slot>
      </${menuTag}>
    `);
    return template;
  }

  refineState(state) {
    let result = super.refineState ? super.refineState(state) : true;
    if (state.opened && !this.opened) {
      // Opening
      if (!state.dragSelect) {
        // Until we get a mouseup, we're doing a drag-select.
        state.dragSelect = true;
        result = false;
      }
      if (state.selectedItem) {
        // Clear any previously selected item.
        state.selectedItem = null;
        result = false;
      }
      if (state.touchstartX !== null || state.touchstartY) {
        // Clear previous touchstart point.
        state.touchstartX = null;
        state.touchstartY = null;
        result = false;
      }
      // Select the default item in the menu.
      const defaultMenuSelectedIndex = this.defaultMenuSelectedIndex;
      if (state.menuSelectedIndex !== defaultMenuSelectedIndex) {
        state.menuSelectedIndex = defaultMenuSelectedIndex;
        result = false;
      }
    } else if (!state.opened && this.opened) {
      // Closing
      if (state.menuSelectedIndex !== -1) {
        // Clear menu selection.
        state.menuSelectedIndex = -1;
        result = false;
      }
    }
    return result;
  }

  get sourceSlotContent() {
    // Default "..." icon from Google Material Design icons.
    return `
      <svg id="ellipsisIcon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
        <path d="M6 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm12 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-6 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/>
      </svg>
    `;
  }

  get updates() {
    const base = super.updates;
    return merge(base, {
      $: {
        menu: {
          style: {
            background: 'window',
            border: 'none',
            'max-height': '100%',
            padding: '0.5em 0'
          },
          selectedIndex: this.state.menuSelectedIndex
        },
        popup: {
          attributes: {
            tabindex: null
          }
        },
        source: {
          style: {
            'align-items': 'center',
            display: 'flex'
          }
        }
      }
    },
    this.$.ellipsisIcon && {
      $: {
        ellipsisIcon: {
          style: {
            display: 'block',
            fill: 'currentColor'
          }
        }
      }
    });
  }

}

function addDocumentListeners(element) {
  document.addEventListener('mouseup', element[documentMouseupListenerKey]);
}

function removeDocumentListeners(element) {
  document.removeEventListener('mouseup', element[documentMouseupListenerKey]);
}

export default MenuButton;
customElements.define('elix-menu-button', MenuButton);
<|endoftext|>


<commit_before>import React, { PropTypes } from 'react';
import uuid from 'uuid';
import { select } from 'd3';

import './style.css';

class Node extends React.Component {

  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
  }

  componentDidMount() {
    const { x, y } = this.props.nodeData;

    select(this.node)
    .transition()
    .duration(500)
    .attr('transform', this.setTransformOrientation(x, y));
  }

  // FIXME unstable re-rendering when regressing to parent coordinates
  setTransformOrientation(x, y) {
    const { orientation } = this.props;
    let transform;

    if (orientation === 'horizontal') {
      // transform = nodeData.parent !== 'null' ?
      //   `translate(${nodeData.parent.y},${nodeData.parent.x})` :
      //   `translate(${nodeData.y},${nodeData.x})`;
      transform = `translate(${y},${x})`;
    } else {
      // transform = nodeData.parent !== 'null' ?
      //   `translate(${nodeData.parent.x},${nodeData.parent.y})` :
      //   `translate(${nodeData.x},${nodeData.y})`;
      transform = `translate(${x},${y})`;
    }

    return transform;
  }

  componentWillLeave(done) {
    const { parent } = this.props.nodeData;

    select(this.node)
    .transition()
    .duration(500)
    .attr('transform', this.setTransformOrientation(parent.x, parent.y))
    .each('end', done);
  }

  handleClick() {
    this.props.onClick(this.props.nodeData.id);
  }

  render() {
    const { nodeData } = this.props;
    return (
      <g
        id={nodeData.id}
        ref={(n) => { this.node = n; }}
        className={nodeData._children ? 'nodeBase' : 'leafNodeBase'}
        transform={this.setTransformOrientation(nodeData.x, nodeData.y)}
        onClick={this.handleClick}
      >
        <text
          className="primaryLabelBase"
          textAnchor={this.props.textAnchor}
          style={this.props.primaryLabelStyle}
          x="10"
          y="-10"
          dy=".35em"
        >
          {this.props.primaryLabel}
        </text>

        <circle
          r={this.props.circleRadius}
          style={nodeData._children ? this.props.circleStyle : this.props.leafCircleStyle}
        />

        <text
          className="secondaryLabelsBase"
          y="0"
          textAnchor={this.props.textAnchor}
          style={this.props.secondaryLabelsStyle}
        >
          {this.props.secondaryLabels && Object.keys(this.props.secondaryLabels).map((labelKey) =>
            <tspan x="10" dy="1.2em" key={uuid.v4()}>
              {labelKey}: {this.props.secondaryLabels[labelKey]}
            </tspan>
          )}
        </text>
      </g>
    );
  }
}

Node.defaultProps = {
  circleRadius: 10,
  circleStyle: {
    stroke: '#000',
    strokeWidth: 2,
    fill: 'grey',
  },
  leafCircleStyle: {
    stroke: '#000',
    strokeWidth: 2,
    fill: 'transparent',
  },
};

/* eslint-disable*/
Node.propTypes = {
  nodeData: PropTypes.object.isRequired,
  orientation: PropTypes.oneOf([
    'horizontal',
    'vertical',
  ]).isRequired,
  onClick: PropTypes.func,
  primaryLabel: PropTypes.string,
  primaryLabelStyle: PropTypes.object,
  secondaryLabels: PropTypes.object,
  secondaryLabelsStyle: PropTypes.object,
  textAnchor: PropTypes.string,
  circleRadius: PropTypes.number,
  circleStyle: PropTypes.object,
  leafCircleStyle: PropTypes.object,
};
/* eslint-enable */

export default Node;
<commit_msg>Simplifies <Node /> export<commit_after>import React, { PropTypes } from 'react';
import uuid from 'uuid';
import { select } from 'd3';

import './style.css';

export default class Node extends React.Component {

  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
  }

  componentDidMount() {
    const { x, y } = this.props.nodeData;

    select(this.node)
    .transition()
    .duration(500)
    .attr('transform', this.setTransformOrientation(x, y));
  }

  // FIXME unstable re-rendering when regressing to parent coordinates
  setTransformOrientation(x, y) {
    const { orientation } = this.props;
    let transform;

    if (orientation === 'horizontal') {
      // transform = nodeData.parent !== 'null' ?
      //   `translate(${nodeData.parent.y},${nodeData.parent.x})` :
      //   `translate(${nodeData.y},${nodeData.x})`;
      transform = `translate(${y},${x})`;
    } else {
      // transform = nodeData.parent !== 'null' ?
      //   `translate(${nodeData.parent.x},${nodeData.parent.y})` :
      //   `translate(${nodeData.x},${nodeData.y})`;
      transform = `translate(${x},${y})`;
    }

    return transform;
  }

  componentWillLeave(done) {
    const { parent } = this.props.nodeData;

    select(this.node)
    .transition()
    .duration(500)
    .attr('transform', this.setTransformOrientation(parent.x, parent.y))
    .each('end', done);
  }

  handleClick() {
    this.props.onClick(this.props.nodeData.id);
  }

  render() {
    const { nodeData } = this.props;
    return (
      <g
        id={nodeData.id}
        ref={(n) => { this.node = n; }}
        className={nodeData._children ? 'nodeBase' : 'leafNodeBase'}
        transform={this.setTransformOrientation(nodeData.x, nodeData.y)}
        onClick={this.handleClick}
      >
        <text
          className="primaryLabelBase"
          textAnchor={this.props.textAnchor}
          style={this.props.primaryLabelStyle}
          x="10"
          y="-10"
          dy=".35em"
        >
          {this.props.primaryLabel}
        </text>

        <circle
          r={this.props.circleRadius}
          style={nodeData._children ? this.props.circleStyle : this.props.leafCircleStyle}
        />

        <text
          className="secondaryLabelsBase"
          y="0"
          textAnchor={this.props.textAnchor}
          style={this.props.secondaryLabelsStyle}
        >
          {this.props.secondaryLabels && Object.keys(this.props.secondaryLabels).map((labelKey) =>
            <tspan x="10" dy="1.2em" key={uuid.v4()}>
              {labelKey}: {this.props.secondaryLabels[labelKey]}
            </tspan>
          )}
        </text>
      </g>
    );
  }
}

Node.defaultProps = {
  circleRadius: 10,
  circleStyle: {
    stroke: '#000',
    strokeWidth: 2,
    fill: 'grey',
  },
  leafCircleStyle: {
    stroke: '#000',
    strokeWidth: 2,
    fill: 'transparent',
  },
};

/* eslint-disable*/
Node.propTypes = {
  nodeData: PropTypes.object.isRequired,
  orientation: PropTypes.oneOf([
    'horizontal',
    'vertical',
  ]).isRequired,
  onClick: PropTypes.func,
  primaryLabel: PropTypes.string,
  primaryLabelStyle: PropTypes.object,
  secondaryLabels: PropTypes.object,
  secondaryLabelsStyle: PropTypes.object,
  textAnchor: PropTypes.string,
  circleRadius: PropTypes.number,
  circleStyle: PropTypes.object,
  leafCircleStyle: PropTypes.object,
};
/* eslint-enable */
<|endoftext|>


<commit_before>'use strict';

import {pick} from 'lodash';
import Highlight from 'react-highlighter';
import React, {PropTypes} from 'react';

import Menu from './Menu.react';
import MenuItem from './MenuItem.react';

import getOptionLabel from './utils/getOptionLabel';

const MATCH_CLASS = 'bootstrap-typeahead-highlight';

const TypeaheadMenu = React.createClass({
  displayName: 'TypeaheadMenu',

  /**
   * In addition to the propTypes below, the following props are automatically
   * passed down by `Typeahead.react`:
   *
   *  - labelKey
   *  - onPaginate
   *  - options
   *  - paginate
   *  - text
   */
  propTypes: {
    /**
     * Provides the ability to specify a prefix before the user-entered text to
     * indicate that the selection will be new. No-op unless `allowNew={true}`.
     */
    newSelectionPrefix: PropTypes.string,
    /**
     * Provides a hook for customized rendering of menu item contents.
     */
    renderMenuItemChildren: PropTypes.func,
  },

  getDefaultProps() {
    return {
      newSelectionPrefix: 'New selection: ',
    };
  },

  render() {
    const menuProps = pick(this.props, [
      'align',
      'className',
      'dropup',
      'emptyLabel',
      'maxHeight',
      'onPaginate',
      'paginate',
      'paginationText',
      'style',
    ]);

    return (
      <Menu {...menuProps}>
        {this.props.options.map(this._renderMenuItem)}
      </Menu>
    );
  },

  _renderMenuItem(option, idx) {
    const {
      labelKey,
      newSelectionPrefix,
      renderMenuItemChildren,
      text,
    } = this.props;

    const menuItemProps = {
      disabled: option.disabled,
      key: idx,
      option,
      position: idx,
    };

    if (option.customOption) {
      return (
        <MenuItem {...menuItemProps}>
          {newSelectionPrefix}
          <Highlight matchClass={MATCH_CLASS} search={text}>
            {option[labelKey]}
          </Highlight>
        </MenuItem>
      );
    }

    return renderMenuItemChildren ?
      <MenuItem {...menuItemProps}>
        {renderMenuItemChildren(this.props, option, idx)}
      </MenuItem> :
      <MenuItem {...menuItemProps}>
        <Highlight matchClass={MATCH_CLASS} search={text}>
          {getOptionLabel(option, labelKey)}
        </Highlight>
      </MenuItem>;
  },
});

export default TypeaheadMenu;
<commit_msg>Update `renderMenuItemChildren` signature<commit_after>'use strict';

import {pick} from 'lodash';
import Highlight from 'react-highlighter';
import React, {PropTypes} from 'react';

import Menu from './Menu.react';
import MenuItem from './MenuItem.react';

import getOptionLabel from './utils/getOptionLabel';

const MATCH_CLASS = 'bootstrap-typeahead-highlight';

const TypeaheadMenu = React.createClass({
  displayName: 'TypeaheadMenu',

  /**
   * In addition to the propTypes below, the following props are automatically
   * passed down by `Typeahead.react`:
   *
   *  - labelKey
   *  - onPaginate
   *  - options
   *  - paginate
   *  - text
   */
  propTypes: {
    /**
     * Provides the ability to specify a prefix before the user-entered text to
     * indicate that the selection will be new. No-op unless `allowNew={true}`.
     */
    newSelectionPrefix: PropTypes.string,
    /**
     * Provides a hook for customized rendering of menu item contents.
     */
    renderMenuItemChildren: PropTypes.func,
  },

  getDefaultProps() {
    return {
      newSelectionPrefix: 'New selection: ',
    };
  },

  render() {
    const menuProps = pick(this.props, [
      'align',
      'className',
      'dropup',
      'emptyLabel',
      'maxHeight',
      'onPaginate',
      'paginate',
      'paginationText',
      'style',
    ]);

    return (
      <Menu {...menuProps}>
        {this.props.options.map(this._renderMenuItem)}
      </Menu>
    );
  },

  _renderMenuItem(option, idx) {
    const {
      labelKey,
      newSelectionPrefix,
      renderMenuItemChildren,
      text,
    } = this.props;

    const menuItemProps = {
      disabled: option.disabled,
      key: idx,
      option,
      position: idx,
    };

    if (option.customOption) {
      return (
        <MenuItem {...menuItemProps}>
          {newSelectionPrefix}
          <Highlight matchClass={MATCH_CLASS} search={text}>
            {option[labelKey]}
          </Highlight>
        </MenuItem>
      );
    }

    return renderMenuItemChildren ?
      <MenuItem {...menuItemProps}>
        {renderMenuItemChildren(option, this.props, idx)}
      </MenuItem> :
      <MenuItem {...menuItemProps}>
        <Highlight matchClass={MATCH_CLASS} search={text}>
          {getOptionLabel(option, labelKey)}
        </Highlight>
      </MenuItem>;
  },
});

export default TypeaheadMenu;
<|endoftext|>


<commit_before>import declare from 'dojo/_base/declare';
import lang from 'dojo/_base/lang';
import string from 'dojo/string';
import List from 'argos/List';

/**
 * @class crm.Views.Contract.List
 *
 * @extends argos.List
 */
const __class = declare('crm.Views.Contract.List', [List], {
  // Templates
  itemTemplate: new Simplate([
    '
{%= $.Account ? $.Account.AccountName : "" %}
',
    '
{%= $.ReferenceNumber %}
',
  ]),

  // Localization
  titleText: 'Contracts',

  // View Properties
  contextView: 'context_dialog',
  detailView: 'contract_detail',
  id: 'contract_list',
  security: 'Entities/Contract/View',
  insertView: 'contract_edit',
  queryOrderBy: 'ReferenceNumber asc',
  querySelect: [
    'Account/AccountName',
    'Contact/FullName',
    'ReferenceNumber',
  ],
  resourceKind: 'contracts',

  formatSearchQuery: function(searchQuery) {
    return string.substitute('(ReferenceNumber like "%${0}%")', [this.escapeSearchQuery(searchQuery)]);
  }
});

lang.setObject('Mobile.SalesLogix.Views.Contract.List', __class);
export default __class;
<commit_msg>Contract eslint<commit_after>import declare from 'dojo/_base/declare';
import lang from 'dojo/_base/lang';
import string from 'dojo/string';
import List from 'argos/List';

/**
 * @class crm.Views.Contract.List
 *
 * @extends argos.List
 */
const __class = declare('crm.Views.Contract.List', [List], {
  // Templates
  itemTemplate: new Simplate([
    '
{%= $.Account ? $.Account.AccountName : "" %}
',
    '
{%= $.ReferenceNumber %}
',
  ]),

  // Localization
  titleText: 'Contracts',

  // View Properties
  contextView: 'context_dialog',
  detailView: 'contract_detail',
  id: 'contract_list',
  security: 'Entities/Contract/View',
  insertView: 'contract_edit',
  queryOrderBy: 'ReferenceNumber asc',
  querySelect: [
    'Account/AccountName',
    'Contact/FullName',
    'ReferenceNumber',
  ],
  resourceKind: 'contracts',

  formatSearchQuery: function formatSearchQuery(searchQuery) {
    return string.substitute('(ReferenceNumber like "%${0}%")', [this.escapeSearchQuery(searchQuery)]);
  },
});

lang.setObject('Mobile.SalesLogix.Views.Contract.List', __class);
export default __class;
<|endoftext|>


<commit_before>import PropTypes from 'prop-types';
import React, { Component } from 'react';
import _ from 'lodash';

const propTypes = {
  page: PropTypes.number.isRequired,
  pageCount: PropTypes.number.isRequired,
  pageSize: PropTypes.number.isRequired,
  onPageChange: PropTypes.func.isRequired,
  autoHidePagination: PropTypes.bool,
};

class Pagination extends Component {
  render() {
    const {
      page,
      pageSize,
      onPageChange,
      autoHidePagination,
    } = this.props;
    let { pageCount } = this.props;
    let hasPrevious = page > 0;
    let hasNext = page < pageCount - 1;
    if (pageSize < 1) {
      pageCount = 1;
      hasPrevious = false;
      hasNext = false;
    }
    if (pageCount > 1 || !autoHidePagination) {
      return (

            <li className={`page-item ${hasPrevious ? '' : 'disabled'}`}>
               {
                  e.preventDefault();
                  if (hasPrevious) {
                    onPageChange(page - 1);
                  }
                }}
              >
                «
                Previous

            {_.times(pageCount, (idx) => (
              <li key={idx} className={`page-item ${idx === page ? 'active' : ''}`}>
                 {
                    e.preventDefault();
                    onPageChange(idx);
                  }}
                >
                  {idx + 1}

            ))}
            <li className={`page-item ${hasNext ? '' : 'disabled'}`}>
               {
                  e.preventDefault();
                  if (hasNext) {
                    onPageChange(page + 1);
                  }
                }}
              >
                »
                Next

      );
    }
    return null;
  }
}

Pagination.propTypes = propTypes;
export default Pagination;
<commit_msg>Pagination maxPageItems: limit number of page items shown<commit_after>import PropTypes from 'prop-types';
import React, { Component } from 'react';
import _ from 'lodash';

const propTypes = {
  page: PropTypes.number.isRequired,
  pageCount: PropTypes.number.isRequired,
  pageSize: PropTypes.number.isRequired,
  onPageChange: PropTypes.func.isRequired,
  autoHidePagination: PropTypes.bool,
};

const pageItem = (idx, page, onPageChange) => (
  <li key={idx} className={`page-item ${idx === page ? 'active' : ''}`}>
     {
        e.preventDefault();
        onPageChange(idx);
      }}
    >
      {idx + 1}

);

// shown pages: first, pagesBeforeCurrent, current, pagesAfterCurrent, last
const pagesBeforeCurrent = 5;
const pagesAfterCurrent = 5;
const currentPageRange = (page, pageCount) => {
  const rangeCount = Math.min(pageCount - 2, pagesBeforeCurrent + pagesAfterCurrent + 1);
  const firstPageMinValue = 1;
  const firstPageMaxValue = pageCount - 1 - rangeCount;
  let firstPage = page - pagesBeforeCurrent;
  firstPage = Math.max(firstPage, firstPageMinValue);
  firstPage = Math.min(firstPage, firstPageMaxValue);
  return _.range(firstPage, firstPage + rangeCount);
};

class Pagination extends Component {
  render() {
    const {
      page,
      pageSize,
      onPageChange,
      autoHidePagination,
    } = this.props;
    let { pageCount } = this.props;
    let hasPrevious = page > 0;
    let hasNext = page < pageCount - 1;
    if (pageSize < 1) {
      pageCount = 1;
      hasPrevious = false;
      hasNext = false;
    }
    if (pageCount > 1 || !autoHidePagination) {
      return (

            <li className={`page-item ${hasPrevious ? '' : 'disabled'}`}>
               {
                  e.preventDefault();
                  if (hasPrevious) {
                    onPageChange(page - 1);
                  }
                }}
              >
                «
                Previous

            { pageItem(0, page, onPageChange) }
            { pageCount > 2 &&
                currentPageRange(page, pageCount).map(idx => pageItem(idx, page, onPageChange))
            }
            { pageCount > 1 && pageItem(pageCount - 1, page, onPageChange) }
            <li className={`page-item ${hasNext ? '' : 'disabled'}`}>
               {
                  e.preventDefault();
                  if (hasNext) {
                    onPageChange(page + 1);
                  }
                }}
              >
                »
                Next

      );
    }
    return null;
  }
}

Pagination.propTypes = propTypes;
export default Pagination;
<|endoftext|>


<commit_before>angular.module('miq.util').factory('chartsMixin', function() {
  'use strict';

  var chartConfig = {
    cpuUsageConfig: {
      chartId: 'cpuUsageChart',
      title: __('CPU'),
      units: __('Cores'),
      usageDataName: __('Used'),
      legendLeftText: __('Last 30 Days'),
      legendRightText: '',
      tooltipType: 'valuePerDay',
      numDays: 30
    },
    memoryUsageConfig: {
      chartId: 'memoryUsageChart',
      title: __('Memory'),
      units: __('GB'),
      usageDataName: __('Used'),
      legendLeftText: __('Last 30 Days'),
      legendRightText: '',
      tooltipType: 'valuePerDay',
      numDays: 30
    },
    hourlyNetworkUsageConfig: {
      chartId    : 'networkUsageCurrentChart',
      headTitle  : __('Hourly Network Utilization'),
      timeFrame  : __('Last 24 hours'),
      units      : __('KBps'),
      dataName   : __('KBps')
    },
    dailyNetworkUsageConfig: {
      chartId  : 'networkUsageDailyChart',
      headTitle: __('Network Utilization Trends'),
      timeFrame: __('Last 30 Days'),
      units    : __('KBps'),
      dataName : __('KBps'),
      tooltipType: 'valuePerDay'
    }
  };

  var processHeatmapData = function(data) {
    if (data) {
      data = _.sortBy(data, 'value');

      return data.map(function(d) {
        var percent = d.value * 100;
        var used = Math.floor(d.value * d.info.total);
        var available = d.info.total - used;
        var tooltip = d.info.node + " : " + d.info.provider + "
" + percent + "%: " + used + " used of " +
          d.info.total + " total
 " + available + " Available";

        return {
          "id": d.id,
          "tooltip": tooltip,
          "value": d.value
        };
      }).reverse()
    }
  };

  return {
    dashboardHeatmapChartHeight:    281,
    nodeHeatMapUsageLegendLabels:   ['< 70%', '70-80%' ,'80-90%', '> 90%'],
    chartConfig: chartConfig,
    processHeatmapData: processHeatmapData
  };
});
<commit_msg>Added hour in network hourly utilization tooltip<commit_after>angular.module('miq.util').factory('chartsMixin', function() {
  'use strict';

  var hourlyTimeTooltip = function(d) {
    var theMoment = moment(d[0].x);
    return _.template('
' +
    '
' +
    '    <%- col1 %>	' +
    '    <%- col2 %>	' +
    '
' +
    '
')({col1: theMoment.format('h:mm A'), col2: d[0].value + ' ' + d[0].name});
  };

  var chartConfig = {
    cpuUsageConfig: {
      chartId: 'cpuUsageChart',
      title: __('CPU'),
      units: __('Cores'),
      usageDataName: __('Used'),
      legendLeftText: __('Last 30 Days'),
      legendRightText: '',
      tooltipType: 'valuePerDay',
      numDays: 30
    },
    memoryUsageConfig: {
      chartId: 'memoryUsageChart',
      title: __('Memory'),
      units: __('GB'),
      usageDataName: __('Used'),
      legendLeftText: __('Last 30 Days'),
      legendRightText: '',
      tooltipType: 'valuePerDay',
      numDays: 30
    },
    hourlyNetworkUsageConfig: {
      chartId    : 'networkUsageCurrentChart',
      headTitle  : __('Hourly Network Utilization'),
      timeFrame  : __('Last 24 hours'),
      units      : __('KBps'),
      dataName   : __('KBps'),
      tooltipFn  : hourlyTimeTooltip
    },
    dailyNetworkUsageConfig: {
      chartId  : 'networkUsageDailyChart',
      headTitle: __('Network Utilization Trends'),
      timeFrame: __('Last 30 Days'),
      units    : __('KBps'),
      dataName : __('KBps'),
      tooltipType: 'valuePerDay'
    }
  };

  var processHeatmapData = function(data) {
    if (data) {
      data = _.sortBy(data, 'value');

      return data.map(function(d) {
        var percent = d.value * 100;
        var used = Math.floor(d.value * d.info.total);
        var available = d.info.total - used;
        var tooltip = d.info.node + " : " + d.info.provider + "
" + percent + "%: " + used + " used of " +
          d.info.total + " total
 " + available + " Available";

        return {
          "id": d.id,
          "tooltip": tooltip,
          "value": d.value
        };
      }).reverse()
    }
  };

  return {
    dashboardHeatmapChartHeight:    281,
    nodeHeatMapUsageLegendLabels:   ['< 70%', '70-80%' ,'80-90%', '> 90%'],
    chartConfig: chartConfig,
    processHeatmapData: processHeatmapData
  };
});
<|endoftext|>