<commit_before>import { join } from 'path';
import { spawn, spawnSync } from 'child_process';

/**
 * Executes a command string.
 *
 * Quite simple in its current state and should be expected to change in the future.
 * Can manage multiple commands if they are divided by either & or &&. Important that there is spacing on both sides.
 *
 * @param {string} command - A command string that should run.
 * @returns {Promise} - A promise that is resolved when all the commands are completed.
 */
export function execute(command) {
    const parallelCommands = command.split(/ & /);
    return executeParallel(parallelCommands);
}

function executeParallel(parallelCommands, path = process.cwd()) {
    const syncCommand = parallelCommands.shift();
    if (syncCommand) {
        return Promise.all([executeCommand(syncCommand, path), executeParallel(parallelCommands, path)]);
    }
    return Promise.resolve();
}

function executeCommand(syncCommand, path = process.cwd()) {
    const syncCommands = syncCommand.split(/ && /);
    return runCommand(syncCommands, path);
}

function runCommand(syncCommands, path = process.cwd()) {
    const command = syncCommands.shift();

    if (command) {
        const parts = command.match(/(?:[^\s"]+|"[^"]*")+/g);
        const cmd = parts[0];
        const args = parts.slice(1);

        // If the command is to change directory we will carry the path over to the next command.
        if (cmd === 'cd') {
            return runCommand(syncCommands, join(path, args[0]));
        }

        return new Promise((resolve, reject) => {
            spawn(cmd, args, { stdio: 'inherit', cwd: path })
                .on('exit', (code) => {
                    if (code !== 0) {
                        return reject(code);
                    }

                    return runCommand(syncCommands, path)
                        .then(resolve)
                        .catch(reject);
                });
        });
    }
    return Promise.resolve();
}

/**
 * Executes a command string in a synchronous manner.
 *
 * Quite simple in its current state and should be expected to change in the future.
 * Can manage multiple commands if they are divided by either & or &&. Important that there is spacing on both sides.
 *
 * @param {string} command - A command string that should run.
 */
export function executeSync(command) {
    // Will run them in parallel anyway, nothing we can do about it currently
    const parallelCommands = command.split(/ & /);
    parallelCommands.forEach((syncCommand) => {
        const syncCommands = syncCommand.split(/ && /);
        const status = runCommandSync(syncCommands);

        if (status) {
            /* eslint-disable no-process-exit */
            process.exit(status);
            /* eslint-enable */
        }
    });
}

function runCommandSync(syncCommands, path = process.cwd()) {
    const command = syncCommands.shift();

    if (command) {
        const parts = command.match(/(?:[^\s"]+|"[^"]*")+/g);
        const cmd = parts[0];
        const args = parts.slice(1);

        // If the command is to change directory we will carry the path over to the next command.
        if (cmd === 'cd') {
            return runCommandSync(syncCommands, join(path, args[0]));
        }

        const { status } = spawnSync(cmd, args, { stdio: 'inherit', cwd: path });

        if (status) {
            return status;
        }

        return runCommandSync(syncCommands, path);
    }
}
<commit_msg>Fixed a small problem with execute and made it a bit more flexible<commit_after>import { join } from 'path';
import { spawn, spawnSync } from 'child_process';

/**
 * Executes a command string.
 *
 * Quite simple in its current state and should be expected to change in the future.
 * Can manage multiple commands if they are divided by either & or &&. Important that there is spacing on both sides.
 *
 * @param {string} command - A command string that should run.
 * @returns {Promise} - A promise that is resolved when all the commands are completed.
 */
export function execute(command) {
    const parallelCommands = command.split(/ & /);
    return executeParallel(parallelCommands);
}

function executeParallel(parallelCommands, path = process.cwd()) {
    const syncCommand = parallelCommands.shift();
    if (syncCommand) {
        return Promise.all([executeCommand(syncCommand, path), executeParallel(parallelCommands, path)]);
    }
    return Promise.resolve();
}

function executeCommand(syncCommand, path = process.cwd()) {
    const syncCommands = syncCommand.split(/ && /);
    return runCommand(syncCommands, path);
}

function runCommand(syncCommands, path = process.cwd()) {
    const command = syncCommands.shift();

    if (command) {
        const parts = getParts(command);
        const cmd = parts[0];
        const args = parts.slice(1);

        // If the command is to change directory we will carry the path over to the next command.
        if (cmd === 'cd') {
            return runCommand(syncCommands, join(path, args[0]));
        }

        return new Promise((resolve, reject) => {
            spawn(cmd, args, { stdio: 'inherit', cwd: path })
                .on('exit', (code) => {
                    if (code !== 0) {
                        return reject(code);
                    }

                    return runCommand(syncCommands, path)
                        .then(resolve)
                        .catch(reject);
                });
        });
    }
    return Promise.resolve();
}

/**
 * Executes a command string in a synchronous manner.
 *
 * Quite simple in its current state and should be expected to change in the future.
 * Can manage multiple commands if they are divided by either & or &&. Important that there is spacing on both sides.
 *
 * @param {string} command - A command string that should run.
 */
export function executeSync(command) {
    // Will run them in parallel anyway, nothing we can do about it currently
    const parallelCommands = command.split(/ & /);
    parallelCommands.forEach((syncCommand) => {
        const syncCommands = syncCommand.split(/ && /);
        const status = runCommandSync(syncCommands);

        if (status) {
            /* eslint-disable no-process-exit */
            process.exit(status);
            /* eslint-enable */
        }
    });
}

function runCommandSync(syncCommands, path = process.cwd()) {
    const command = syncCommands.shift();

    if (command) {
        const parts = getParts(command);
        const cmd = parts[0];
        const args = parts.slice(1);

        // If the command is to change directory we will carry the path over to the next command.
        if (cmd === 'cd') {
            return runCommandSync(syncCommands, join(path, args[0]));
        }

        const { status } = spawnSync(cmd, args, { stdio: 'inherit', cwd: path });

        if (status) {
            return status;
        }

        return runCommandSync(syncCommands, path);
    }
}

/**
 * Will take a command string an return an array with the different parts of the command.
 *
 * Will manage command parts that has been grouped with " or '.
 *
 * @param {string} commandString - The string to split up into parts.
 *
 * @returns {string[]} - An array with the different parts of the command.
 */
function getParts(commandString) {
    const regex = /[^\s"']+|"([^"]*)"|'([^']*)'/g;
    const parts = [];
    let match;

    while ((match = regex.exec(commandString))) {
        parts.push(match[1] || match[2] || match[0]);
    }

    return parts;
}
<|endoftext|>


<commit_before>$(document).ready(function () {
    $('#myTab a:first').tab('show');
//     $('#myTab a[href="#mem_mgmt"]').tab('show');
    $('#myModal').modal({show: false, backdrop: "static"});

//     $('#myDropdown').on('hide.bs.dropdown', function () {
//         console.debug("OKOK", $('#myDropdown').dropdown());
//     });

    initOrgStruc();
    initPath();
    initWidgets();

//     initAssign();
    initMemberList(mems);
});
<commit_msg>Added debug output<commit_after>$(document).ready(function () {
    console.debug("pade loaded");
//     $("#saveBtn").on("click", function () {
//         console.debug("tool clicked");
//     });
});

/*
$(document).ready(function () {
    $('#myTab a:first').tab('show');
//     $('#myTab a[href="#mem_mgmt"]').tab('show');
    $('#myModal').modal({show: false, backdrop: "static"});

//     $('#myDropdown').on('hide.bs.dropdown', function () {
//         console.debug("OKOK", $('#myDropdown').dropdown());
//     });

    initOrgStruc();
    initPath();
    initWidgets();

//     initAssign();
    initMemberList(mems);
});
*/
<|endoftext|>


<commit_before>var markdownpdf = require("markdown-pdf");
var fs = require("fs");
var split = require("split");
var through = require("through");
var duplexer = require("duplexer");

function preprocessMd() {
    var splitter = split();
    var replacer = through(function(d) {
	this.queue(
	    d.replace(/^\^/, "<pagebreak>").
		replace(/^---/, "<pagebreak>") + "\n");
    });
    splitter.pipe(replacer);
    return duplexer(splitter, replacer);
}

fs.createReadStream("content.md").
    pipe(markdownpdf({
	paperOrientation: "landscape",
	cssPath: "pdf.css",
	remarkable: {
	    html: true,
	    breaks: true,
	    typographer: true
	},
	preProcessMd: preprocessMd
    })).
    pipe(fs.createWriteStream("slidecontent.pdf"));

<commit_msg>fixing replacement in topdf<commit_after>var markdownpdf = require("markdown-pdf");
var fs = require("fs");
var split = require("split");
var through = require("through");
var duplexer = require("duplexer");

function preprocessMd() {
    var splitter = split();
    var replacer = through(function(d) {
	this.queue(
	    d.replace(/^\^$/, "<pagebreak>").
		replace(/^---$/, "<pagebreak>") + "\n");
    });
    splitter.pipe(replacer);
    return duplexer(splitter, replacer);
}

fs.createReadStream("content.md").
    pipe(markdownpdf({
	paperOrientation: "landscape",
	cssPath: "pdf.css",
	remarkable: {
	    html: true,
	    breaks: true,
	    typographer: true
	},
	preProcessMd: preprocessMd
    })).
    pipe(fs.createWriteStream("slidecontent.pdf"));

<|endoftext|>


<commit_before>// style.js
const path = require('path');

function Style(file){
	this.file = file;
}

Style.create = function(file){
	return new Style(file);
}

Style.prototype.toTag = function(){
	let ext = path.parse(this.file);

	if (ext === '.js'){
		return this.toJSTag();
	} else {
		return this.toLinkTag();
	}
}

Style.prototype.toLinkTag = function(){
	return `<link rel="stylesheet" href="/css/${this.file}">`
}

Style.prototype.toJSTag = function(){
	return `<script src="/js/${this.file}"></script>`;
}

var item2tag = item => Style.create(item).toTag();

let styleTable = {
	home: [
		'home.css'
	],
	cate: [
		'cate.css'
	],
	cates: [
		'cates.css'
	],
	blog: [
		'blog.css'
	]
}

let publicFiles = [
	'flexible.min.js',
	'__________.css'
].map(item2tag)

module.exports = function(name){
	let fileArr = styleTable[name];

	return publicFiles.join('') + fileArr.map(item2tag).join('');
}
<commit_msg>还是刚刚的 Bug (style.js 输出的在浏览器里报 404), 已经解决<commit_after>// style.js
const path = require('path');

var file2tag = item => {
	let o = path.parse(item);
	let ext = o.ext

	if (ext === '.js'){
		return `<script src="/js/${item}"></script>`;
	} else {
		return `<link rel="stylesheet" href="/css/${item}">`
	}
}

let styleTable = {
	home: [
		'home.css'
	],
	cate: [
		'cate.css'
	],
	cates: [
		'cates.css'
	],
	blog: [
		'blog.css'
	]
}

let publicFiles = [
	'flexible.min.js',
	'__________.css'
].map(file2tag).join('');

module.exports = function(name){
	let fileArr = styleTable[name];

	return publicFiles + fileArr.map(file2tag).join('');
}
<|endoftext|>


<commit_before>/*
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
  Actions are high-level executable behaviours that are typically
  triggered by users and represented as buttons or menus.

  Actions are installed as methods on the class, but contain more
  meta-information than regular methods. Meta-information includes
  information needed to surface to action in a meaningful way to
  users, and includes things like the label to appear in the button
  or menu, a speech-label for i18n, help text, dynamic functions to
  enable or disable and hide or unhide the UI associated with this Action.

  Actions implement the Action Design Pattern.
*/
foam.CLASS({
  package: 'foam.core',
  name: 'Action',

  properties: [
    {
      class: 'String',
      name: 'name',
      required: true
    },
    {
      class: 'String',
      name: 'label',
      expression: function(name) { return foam.String.labelize(name); }
    },
    {
      class: 'String',
      name: 'speechLabel',
      expression: function(label) { return label; }
    },
    {
      class: 'String',
      name: 'help'
    },
    {
      class: 'Boolean',
      name: 'isDefault',
      help: 'Indicates if this is the default action.',
      value: false
    },
    {
      class: 'Function',
      name: 'isAvailable',
      label: 'Available',
      // FUTURE: make dynamic
      value: function() { return true; },
      help: 'Function to determine if action is available.'
    },
    {
      class: 'Function',
      name: 'isEnabled',
      label: 'Enabled',
      // FUTURE: make dynamic
      value: function() { return true; },
      help: 'Function to determine if action is enabled.'
    },
    {
      class: 'Function',
      name: 'code',
      required: true,
      value: null
    }
  ],

  methods: [
    function maybeCall(ctx, that) {
      if ( this.isAvailable.call(that, this) && this.isEnabled.call(that, this) ) {
        this.code.call(that, ctx, this);
        that.pub('action', this.name, this);
        return true;
      }
      return false;
    },

    function installInProto(proto) {
      var action = this;
      proto[this.name] = function() {
        return action.maybeCall(this.__context__, this);
      };
    }
  ]
});

/** Add Action support to Model. */
foam.CLASS({
  refines: 'foam.core.Model',

  properties: [
    {
      class: 'AxiomArray',
      of: 'Action',
      name: 'actions',
      adaptArrayElement: function(o, prop) {
        return typeof o === 'function' ?
            foam.core.Action.create({name: o.name, code: o}) :
            foam.lookup(prop.of).create(o) ;
      }
    }
  ]
});
<commit_msg>Actions now install class constants.<commit_after>/*
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
  Actions are high-level executable behaviours that are typically
  triggered by users and represented as buttons or menus.

  Actions are installed as methods on the class, but contain more
  meta-information than regular methods. Meta-information includes
  information needed to surface to action in a meaningful way to
  users, and includes things like the label to appear in the button
  or menu, a speech-label for i18n, help text, dynamic functions to
  enable or disable and hide or unhide the UI associated with this Action.

  Actions implement the Action Design Pattern.
*/
foam.CLASS({
  package: 'foam.core',
  name: 'Action',

  properties: [
    {
      class: 'String',
      name: 'name',
      required: true
    },
    {
      class: 'String',
      name: 'label',
      expression: function(name) { return foam.String.labelize(name); }
    },
    {
      class: 'String',
      name: 'speechLabel',
      expression: function(label) { return label; }
    },
    {
      class: 'String',
      name: 'help'
    },
    {
      class: 'Boolean',
      name: 'isDefault',
      help: 'Indicates if this is the default action.',
      value: false
    },
    {
      class: 'Function',
      name: 'isAvailable',
      label: 'Available',
      // FUTURE: make dynamic
      value: function() { return true; },
      help: 'Function to determine if action is available.'
    },
    {
      class: 'Function',
      name: 'isEnabled',
      label: 'Enabled',
      // FUTURE: make dynamic
      value: function() { return true; },
      help: 'Function to determine if action is enabled.'
    },
    {
      class: 'Function',
      name: 'code',
      required: true,
      value: null
    }
  ],

  methods: [
    function maybeCall(ctx, that) {
      if ( this.isAvailable.call(that, this) && this.isEnabled.call(that, this) ) {
        this.code.call(that, ctx, this);
        that.pub('action', this.name, this);
        return true;
      }
      return false;
    },

    function installInClass(c) {
      c.installConstant(this.name, this);
    },

    function installInProto(proto) {
      var action = this;
      proto[this.name] = function() {
        return action.maybeCall(this.__context__, this);
      };
    }
  ]
});

/** Add Action support to Model. */
foam.CLASS({
  refines: 'foam.core.Model',

  properties: [
    {
      class: 'AxiomArray',
      of: 'Action',
      name: 'actions',
      adaptArrayElement: function(o, prop) {
        return typeof o === 'function' ?
            foam.core.Action.create({name: o.name, code: o}) :
            foam.lookup(prop.of).create(o) ;
      }
    }
  ]
});
<|endoftext|>


<commit_before>//Based on https://github.com/arasatasaygin/is.js/blob/master/is.js
require('../polyfill/index');

var userAgent = 'navigator' in window && 'userAgent' in navigator && navigator.userAgent.toLowerCase() || '',
    vendor = 'navigator' in window && 'vendor' in navigator && navigator.vendor.toLowerCase() || '',
    appVersion = 'navigator' in window && 'appVersion' in navigator && navigator.appVersion.toLowerCase() || '';

//Browsers
var isChrome = /chrome|chromium/i.test(userAgent) && /google inc/.test(vendor),
    isFirefox = /firefox/i.test(userAgent),
    isIE = /msie/i.test(userAgent) || "ActiveXObject" in window,
    isOpera = /^Opera\//.test(userAgent) || /\x20OPR\//.test(userAgent),
    isSafari = /safari/i.test(userAgent) && /apple computer/i.test(vendor);

//Devices && OS
var isIphone = /iphone/i.test(userAgent),
    isIpad = /ipad/i.test(userAgent),
    isIpod = /ipod/i.test(userAgent),
    isAndroid = /android/i.test(userAgent),
    isAndroidPhone = /android/i.test(userAgent) && /mobile/i.test(userAgent),
    isAndroidTablet = /android/i.test(userAgent) && !/mobile/i.test(userAgent),
    isLinux = /linux/i.test(appVersion),
    isMac = /mac/i.test(appVersion),
    isWindow = /win/i.test(appVersion),
    isWindowPhone = isWindow && /phone/i.test(userAgent),
    isWindowTablet = isWindow && !isWindowPhone && /touch/i.test(userAgent),
    isMobile = isIphone || isIpod|| isAndroidPhone || isWindowPhone,
    isTablet = isIpad || isAndroidTablet || isWindowTablet,
    isDesktop = !isMobile && !isTablet,
    isTouchDevice = 'ontouchstart' in window ||'DocumentTouch' in window && document instanceof DocumentTouch,
    isCocoon = !!navigator.isCocoonJS,
    isNodeWebkit = typeof process === "object" && process.title === "node" && typeof global === "object",
    isEjecta = !!window.ejecta,
    isCrosswalk = /Crosswalk/.test(userAgent),
    isCordova = !!window.cordova;

var hasVibrate = !!navigator.vibrate && (isMobile || isTablet),
    hasMouseWheel = 'onwheel' in window || 'onmousewheel' in window || 'MouseScrollEvent' in window,
    hasAccelerometer = 'DeviceMotionEvent' in window;

//FullScreen
var div = document.createElement('div');
var fullScreenRequest = div.requestFullscreen || div.webkitRequestFullScreen || div.msRequestFullScreen || div.mozRequestFullScreen,
    fullScreenCancel = document.cancelFullScreen || document.exitFullScreen || document.webkitCancelFullScreen || document.msCancelFullScreen || document.mozCancelFullScreen,
    hasFullScreen = !!(fullScreenRequest && fullScreenCancel);

//TODO: Check audio support, fullScreensupport, etc...

var Device = module.exports = {
    isChrome : isChrome,
    isFirefox : isFirefox,
    isIE : isIE,
    isOpera : isOpera,
    isSafari : isSafari,
    isIphone : isIphone,
    isIpad : isIpad,
    isIpod : isIpod,
    isAndroid : isAndroid,
    isAndroidPhone : isAndroidPhone,
    isAndroidTablet : isAndroidTablet,
    isLinux : isLinux,
    isMac : isMac,
    isWindow : isWindow,
    isWindowPhone : isWindowPhone,
    isWindowTablet : isWindowTablet,
    isMobile : isMobile,
    isTablet : isTablet,
    isDesktop : isDesktop,
    isTouchDevice : isTouchDevice,
    isCocoon : isCocoon,
    isNodeWebkit : isNodeWebkit,
    isEjecta : isEjecta,
    isCordova : isCordova,
    isCrosswalk : isCrosswalk,

    //isOnline : navigator.onLine,
    hasVibrate : hasVibrate,
    hasMouseWheel : hasMouseWheel,
    hasFullScreen : hasFullScreen,
    hasAccelerometer : hasAccelerometer,

    fullScreenRequest : fullScreenRequest ? fullScreenRequest.name : undefined,
    fullScreenCancel : fullScreenCancel ? fullScreenCancel.name : undefined,

    getMouseWheelEvent : function(){
        if(!hasMouseWheel)return;
        var evt;
        if('onwheel' in window){
            evt = 'wheel';
        }else if('onmousewheel' in window){
            evt = 'mousewheel';
        }else if('MouseScrollEvent' in window){
            evt = 'DOMMouseScroll';
        }

        return evt;
    },

    vibrate : function(value){
        if(hasVibrate){
            navigator.vibrate(value);
        }
    }
};

Object.defineProperties(Device, {
    isOnline: {
        get : function() {
            return window.navigator.onLine;
        }
    }
});<commit_msg>added environment check for electron (atom-shell)<commit_after>//Based on https://github.com/arasatasaygin/is.js/blob/master/is.js
require('../polyfill/index');

var userAgent = 'navigator' in window && 'userAgent' in navigator && navigator.userAgent.toLowerCase() || '',
    vendor = 'navigator' in window && 'vendor' in navigator && navigator.vendor.toLowerCase() || '',
    appVersion = 'navigator' in window && 'appVersion' in navigator && navigator.appVersion.toLowerCase() || '';

//Browsers
var isChrome = /chrome|chromium/i.test(userAgent) && /google inc/.test(vendor),
    isFirefox = /firefox/i.test(userAgent),
    isIE = /msie/i.test(userAgent) || "ActiveXObject" in window,
    isOpera = /^Opera\//.test(userAgent) || /\x20OPR\//.test(userAgent),
    isSafari = /safari/i.test(userAgent) && /apple computer/i.test(vendor);

//Devices && OS
var isIphone = /iphone/i.test(userAgent),
    isIpad = /ipad/i.test(userAgent),
    isIpod = /ipod/i.test(userAgent),
    isAndroid = /android/i.test(userAgent),
    isAndroidPhone = /android/i.test(userAgent) && /mobile/i.test(userAgent),
    isAndroidTablet = /android/i.test(userAgent) && !/mobile/i.test(userAgent),
    isLinux = /linux/i.test(appVersion),
    isMac = /mac/i.test(appVersion),
    isWindow = /win/i.test(appVersion),
    isWindowPhone = isWindow && /phone/i.test(userAgent),
    isWindowTablet = isWindow && !isWindowPhone && /touch/i.test(userAgent),
    isMobile = isIphone || isIpod|| isAndroidPhone || isWindowPhone,
    isTablet = isIpad || isAndroidTablet || isWindowTablet,
    isDesktop = !isMobile && !isTablet,
    isTouchDevice = 'ontouchstart' in window ||'DocumentTouch' in window && document instanceof DocumentTouch,
    isCocoon = !!navigator.isCocoonJS,
    isNodeWebkit = typeof process === "object" && process.title === "node" && typeof global === "object",
    isEjecta = !!window.ejecta,
    isCrosswalk = /Crosswalk/.test(userAgent),
    isCordova = !!window.cordova,
    isElectron = process && process.versions && (process.versions['electron'] || process.versions['atom-shell']);

var hasVibrate = !!navigator.vibrate && (isMobile || isTablet),
    hasMouseWheel = 'onwheel' in window || 'onmousewheel' in window || 'MouseScrollEvent' in window,
    hasAccelerometer = 'DeviceMotionEvent' in window;

//FullScreen
var div = document.createElement('div');
var fullScreenRequest = div.requestFullscreen || div.webkitRequestFullScreen || div.msRequestFullScreen || div.mozRequestFullScreen,
    fullScreenCancel = document.cancelFullScreen || document.exitFullScreen || document.webkitCancelFullScreen || document.msCancelFullScreen || document.mozCancelFullScreen,
    hasFullScreen = !!(fullScreenRequest && fullScreenCancel);

//TODO: Check audio support, fullScreensupport, etc...

var Device = module.exports = {
    isChrome : isChrome,
    isFirefox : isFirefox,
    isIE : isIE,
    isOpera : isOpera,
    isSafari : isSafari,
    isIphone : isIphone,
    isIpad : isIpad,
    isIpod : isIpod,
    isAndroid : isAndroid,
    isAndroidPhone : isAndroidPhone,
    isAndroidTablet : isAndroidTablet,
    isLinux : isLinux,
    isMac : isMac,
    isWindow : isWindow,
    isWindowPhone : isWindowPhone,
    isWindowTablet : isWindowTablet,
    isMobile : isMobile,
    isTablet : isTablet,
    isDesktop : isDesktop,
    isTouchDevice : isTouchDevice,
    isCocoon : isCocoon,
    isNodeWebkit : isNodeWebkit,
    isEjecta : isEjecta,
    isCordova : isCordova,
    isCrosswalk : isCrosswalk,
    isElectron : isElectron,
    isAtomShell : isElectron, //TODO: Remove soon, when atom-shell (version) is deprecated

    //isOnline : navigator.onLine,
    hasVibrate : hasVibrate,
    hasMouseWheel : hasMouseWheel,
    hasFullScreen : hasFullScreen,
    hasAccelerometer : hasAccelerometer,

    fullScreenRequest : fullScreenRequest ? fullScreenRequest.name : undefined,
    fullScreenCancel : fullScreenCancel ? fullScreenCancel.name : undefined,

    getMouseWheelEvent : function(){
        if(!hasMouseWheel)return;
        var evt;
        if('onwheel' in window){
            evt = 'wheel';
        }else if('onmousewheel' in window){
            evt = 'mousewheel';
        }else if('MouseScrollEvent' in window){
            evt = 'DOMMouseScroll';
        }

        return evt;
    },

    vibrate : function(value){
        if(hasVibrate){
            navigator.vibrate(value);
        }
    }
};

Object.defineProperties(Device, {
    isOnline: {
        get : function() {
            return window.navigator.onLine;
        }
    }
});<|endoftext|>


<commit_before>var expect = require('chai').expect;
var sinon = require('sinon');
var DateUtils = require('../dist/x-date-core.test_only.js').DateUtils;
var config = require('../dist/x-date-core.test_only.js').Config;

describe("Date Utils", function () {

    it("is module an object", function () {
        expect(DateUtils).to.be.a('object');
        expect(Object.getPrototypeOf(DateUtils)).to.be.a('object');
    });

    describe("Check UTC functions", function () {
        var isUtcBuffer = config.isUtc;
        var date = new Date(2015, 1, 1).getTime();

        beforeEach(function () {
            config.isUtc = true;
        });

        afterEach(function () {
            config.isUtc = isUtcBuffer;
        });

        describe("getDay", function () {

            it("common case", function () {
                expect(DateUtils.getDay(date)).to.be.equal(new Date(date).getUTCDate());
            });

            it("NaN arg", function () {
                return expect(DateUtils.getDay('random text')).to.be.NaN;
            });

            it("string num arg", function () {
                expect(DateUtils.getDay(date.toString())).to.be.equal(new Date(date).getUTCDate());
            });

            it("infinity case", function () {
                return expect(DateUtils.getDay(Infinity)).to.be.NaN;
            });

            it("no args case", function () {
                return expect(DateUtils.getDay()).to.be.NaN;
            });
        });

        describe("getDayOfWeek", function () {

            it("common case", function () {
                expect(DateUtils.getDayOfWeek(date)).to.be.equal(new Date(date).getUTCDay());
            });

            it("NaN arg", function () {
                return expect(DateUtils.getDayOfWeek('random text')).to.be.NaN;
            });

            it("string num arg", function () {
                expect(DateUtils.getDayOfWeek(date.toString())).to.be.equal(new Date(date).getUTCDay());
            });

            it("infinity case", function () {
                return expect(DateUtils.getDayOfWeek(Infinity)).to.be.NaN;
            });

            it("no args case", function () {
                return expect(DateUtils.getDayOfWeek()).to.be.NaN;
            });
        });

        describe("getYear", function () {

            it("common case", function () {
                expect(DateUtils.getYear(date)).to.be.equal(new Date(date).getUTCFullYear());
            });

            it("NaN arg", function () {
                return expect(DateUtils.getYear('random text')).to.be.NaN;
            });

            it("string num arg", function () {
                expect(DateUtils.getYear(date.toString())).to.be.equal(new Date(date).getUTCFullYear());
            });

            it("infinity case", function () {
                return expect(DateUtils.getYear(Infinity)).to.be.NaN;
            });

            it("no args case", function () {
                return expect(DateUtils.getYear()).to.be.NaN;
            });
        });

        describe("getMonth", function () {

            it("common case", function () {
                expect(DateUtils.getMonth(date)).to.be.equal(new Date(date).getUTCMonth());
            });

            it("NaN arg", function () {
                return expect(DateUtils.getMonth('random text')).to.be.NaN;
            });

            it("string num arg", function () {
                expect(DateUtils.getMonth(date.toString())).to.be.equal(new Date(date).getUTCMonth());
            });

            it("infinity case", function () {
                return expect(DateUtils.getMonth(Infinity)).to.be.NaN;
            });

            it("no args case", function () {
                return expect(DateUtils.getMonth()).to.be.NaN;
            });
        });

        describe("getDaysInMonth", function () {

            it("common case", function () {
                var year = 2015;
                var month = 1;
                var resultDate = new Date(year, month + 1, 0);
                expect(DateUtils.getDaysInMonth(month, year)).to.be.equal(resultDate.getUTCDate());
            });

            it("NaN arg", function () {
                return expect(DateUtils.getDaysInMonth('random text')).to.be.NaN;
            });

            it("string num arg", function () {
                var year = 2015;
                var month = 1;
                var resultDate = new Date(year, month + 1, 0);
                expect(DateUtils.getDaysInMonth(month.toString(), year.toString())).to.be.equal(resultDate.getUTCDate());
            });

            it("infinity case", function () {
                return expect(DateUtils.getDaysInMonth(Infinity)).to.be.NaN;
            });

            it("no args case", function () {
                return expect(DateUtils.getDaysInMonth()).to.be.NaN;
            });
        });

    });

    describe("isValidModel", function () {

        it("common case", function () {
            var model = {dt: 1};
            return expect(DateUtils.isValidModel(model)).to.be.true;
        });

        it("empty model", function () {
            var model = {};
            return expect(DateUtils.isValidModel(model)).to.be.false;
        });

        it("null model", function () {
            var model = null;
            return expect(DateUtils.isValidModel(model)).to.be.false;
        });

        it("array model", function () {
            var model = [];
            return expect(DateUtils.isValidModel(model)).to.be.false;
        });

        it("primitive model", function () {
            var model = 123;
            return expect(DateUtils.isValidModel(model)).to.be.false;
        });

        it("null datetime in model", function () {
            var model = {dt: null};
            return expect(DateUtils.isValidModel(model)).to.be.false;
        });

        it("infinity datetime", function () {
            var model = {dt: Infinity};
            return expect(DateUtils.isValidModel(model)).to.be.false;
        });

        it("string number datetime model", function () {
            var model = {dt: "123"};
            return expect(DateUtils.isValidModel(model)).to.be.true;
        });

        it("string datetime model", function () {
            var model = {dt: "some"};
            return expect(DateUtils.isValidModel(model)).to.be.false;
        });

        it("model dt is 0", function () {
            var model = {dt: 0};
            return expect(DateUtils.isValidModel(model)).to.be.true;
        });

    });

    describe("isDateUpperStartLimit", function () {

        it("datetime > start limit", function () {
            var dt = new Date(2015, 1, 2).getTime();
            var start = new Date(2015, 1, 1).getTime();

            return expect(DateUtils.isDateUpperStartLimit(dt, start)).to.be.true;
        });

        it("datetime < start limit", function () {
            var dt = new Date(2015, 1, 1).getTime();
            var start = new Date(2015, 1, 2).getTime();

            return expect(DateUtils.isDateUpperStartLimit(dt, start)).to.be.false;
        });

        it("datetime equal start limit", function () {
            var dt = new Date(2015, 1, 1).getTime();
            var start = new Date(2015, 1, 1).getTime();

            return expect(DateUtils.isDateUpperStartLimit(dt, start)).to.be.false;
        });

        it("no datetime", function () {
            var start = new Date(2015, 1, 1).getTime();

            //var spy = sinon.spy(DateUtils, 'isDateUpperStartLimit');
            return expect(function () {
                DateUtils.isDateUpperStartLimit(undefined, start);
            }).to.throw('NaN or null');
            //DateUtils.isDateUpperStartLimit.restore();
        });

        it("no start limit", function () {
            var dt = new Date(2015, 1, 1).getTime();
            return expect(DateUtils.isDateUpperStartLimit(dt, undefined)).to.be.true;
        });

        it("no args", function () {
            return expect(DateUtils.isDateUpperStartLimit()).to.be.true;
        });

        it("string args and datetime < start limit", function () {
            var dt = new Date(2015, 1, 1).getTime().toString();
            var start = new Date(2015, 1, 2).getTime().toString();

            return expect(DateUtils.isDateUpperStartLimit(dt, start)).to.be.false;
        });

        it("string args and datetime > start limit", function () {
            var dt = new Date(2015, 1, 2).getTime().toString();
            var start = new Date(2015, 1, 1).getTime().toString();

            return expect(DateUtils.isDateUpperStartLimit(dt, start)).to.be.true;
        });

        it("string args and datetime equal to start limit", function () {
            var dt = new Date(2015, 1, 1).getTime().toString();
            var start = new Date(2015, 1, 1).getTime().toString();

            return expect(DateUtils.isDateUpperStartLimit(dt, start)).to.be.false;
        });

        it("Infinity start", function () {
            var dt = new Date(2015, 1, 1).getTime();
            var start = Infinity;

            return expect(DateUtils.isDateUpperStartLimit(dt, start)).to.be.false;
        });

        it("Infinity datetime", function () {
            var dt = Infinity;
            var start = new Date(2015, 1, 1).getTime();

            return expect(DateUtils.isDateUpperStartLimit(dt, start)).to.be.true;
        });

        it("NaN datetime", function () {
            var dt = 'Adasdsd';
            var start = new Date(2015, 1, 1).getTime();

            //var spy = sinon.spy(DateUtils, 'isDateUpperStartLimit');
            return expect(function () {
                DateUtils.isDateUpperStartLimit(dt, start);
            }).to.throw('NaN or null');
            //DateUtils.isDateUpperStartLimit.restore();

        });

    });

    describe("isDateLowerEndLimit", function () {
        //TODO (S.Panfilov)
    });

    describe("isDateBetweenLimits", function () {
        //TODO (S.Panfilov)
    });

    describe("getVal", function () {

        it("common case", function () {
            var datetime = new Date(2015, 1, 1).getTime();
            var method = Date.prototype.getDate;
            var result = new Date(datetime).getDate();

            expect(DateUtils._private.getVal(datetime, method)).to.be.equal(result);
        });

        it("not date method", function () {
            var datetime = new Date(2015, 1, 1).getTime();
            var expectVal = 123;
            var method = function () {
                return expectVal;
            };

            return expect(DateUtils._private.getVal(datetime, method)).to.be.equal(expectVal);
        });

        it("no method", function () {
            var datetime = new Date(2015, 1, 1).getTime();
            return expect(DateUtils._private.getVal(datetime)).to.be.null;
        });

        it("no date", function () {
            var method = Date.prototype.getDate;
            return expect(DateUtils._private.getVal(undefined, method)).to.be.NaN;
        });

        it("string num datetime", function () {
            var datetime = new Date(2015, 1, 1).getTime();
            var method = Date.prototype.getDate;
            var result = new Date(datetime).getDate();

            expect(DateUtils._private.getVal(datetime.toString(), method)).to.be.equal(result);
        });

        it("string datetime", function () {
            var method = Date.prototype.getDate;

            return expect(DateUtils._private.getVal(undefined, method)).to.be.NaN;
        });

        it("no args", function () {
            return expect(DateUtils._private.getVal()).to.be.null;
        });

    });
});<commit_msg>add more tests<commit_after>var expect = require('chai').expect;
var sinon = require('sinon');
var DateUtils = require('../dist/x-date-core.test_only.js').DateUtils;
var config = require('../dist/x-date-core.test_only.js').Config;

describe("Date Utils", function () {

    it("is module an object", function () {
        expect(DateUtils).to.be.a('object');
        expect(Object.getPrototypeOf(DateUtils)).to.be.a('object');
    });

    describe("Check UTC functions", function () {
        var isUtcBuffer = config.isUtc;
        var date = new Date(2015, 1, 1).getTime();

        beforeEach(function () {
            config.isUtc = true;
        });

        afterEach(function () {
            config.isUtc = isUtcBuffer;
        });

        describe("getDay", function () {

            it("common case", function () {
                expect(DateUtils.getDay(date)).to.be.equal(new Date(date).getUTCDate());
            });

            it("NaN arg", function () {
                return expect(DateUtils.getDay('random text')).to.be.NaN;
            });

            it("string num arg", function () {
                expect(DateUtils.getDay(date.toString())).to.be.equal(new Date(date).getUTCDate());
            });

            it("infinity case", function () {
                return expect(DateUtils.getDay(Infinity)).to.be.NaN;
            });

            it("no args case", function () {
                return expect(DateUtils.getDay()).to.be.NaN;
            });
        });

        describe("getDayOfWeek", function () {

            it("common case", function () {
                expect(DateUtils.getDayOfWeek(date)).to.be.equal(new Date(date).getUTCDay());
            });

            it("NaN arg", function () {
                return expect(DateUtils.getDayOfWeek('random text')).to.be.NaN;
            });

            it("string num arg", function () {
                expect(DateUtils.getDayOfWeek(date.toString())).to.be.equal(new Date(date).getUTCDay());
            });

            it("infinity case", function () {
                return expect(DateUtils.getDayOfWeek(Infinity)).to.be.NaN;
            });

            it("no args case", function () {
                return expect(DateUtils.getDayOfWeek()).to.be.NaN;
            });
        });

        describe("getYear", function () {

            it("common case", function () {
                expect(DateUtils.getYear(date)).to.be.equal(new Date(date).getUTCFullYear());
            });

            it("NaN arg", function () {
                return expect(DateUtils.getYear('random text')).to.be.NaN;
            });

            it("string num arg", function () {
                expect(DateUtils.getYear(date.toString())).to.be.equal(new Date(date).getUTCFullYear());
            });

            it("infinity case", function () {
                return expect(DateUtils.getYear(Infinity)).to.be.NaN;
            });

            it("no args case", function () {
                return expect(DateUtils.getYear()).to.be.NaN;
            });
        });

        describe("getMonth", function () {

            it("common case", function () {
                expect(DateUtils.getMonth(date)).to.be.equal(new Date(date).getUTCMonth());
            });

            it("NaN arg", function () {
                return expect(DateUtils.getMonth('random text')).to.be.NaN;
            });

            it("string num arg", function () {
                expect(DateUtils.getMonth(date.toString())).to.be.equal(new Date(date).getUTCMonth());
            });

            it("infinity case", function () {
                return expect(DateUtils.getMonth(Infinity)).to.be.NaN;
            });

            it("no args case", function () {
                return expect(DateUtils.getMonth()).to.be.NaN;
            });
        });

        describe("getDaysInMonth", function () {

            it("common case", function () {
                var year = 2015;
                var month = 1;
                var resultDate = new Date(year, month + 1, 0);
                expect(DateUtils.getDaysInMonth(month, year)).to.be.equal(resultDate.getUTCDate());
            });

            it("NaN arg", function () {
                return expect(DateUtils.getDaysInMonth('random text')).to.be.NaN;
            });

            it("string num arg", function () {
                var year = 2015;
                var month = 1;
                var resultDate = new Date(year, month + 1, 0);
                expect(DateUtils.getDaysInMonth(month.toString(), year.toString())).to.be.equal(resultDate.getUTCDate());
            });

            it("infinity case", function () {
                return expect(DateUtils.getDaysInMonth(Infinity)).to.be.NaN;
            });

            it("no args case", function () {
                return expect(DateUtils.getDaysInMonth()).to.be.NaN;
            });
        });

    });

    describe("isValidModel", function () {

        it("common case", function () {
            var model = {dt: 1};
            return expect(DateUtils.isValidModel(model)).to.be.true;
        });

        it("empty model", function () {
            var model = {};
            return expect(DateUtils.isValidModel(model)).to.be.false;
        });

        it("null model", function () {
            var model = null;
            return expect(DateUtils.isValidModel(model)).to.be.false;
        });

        it("array model", function () {
            var model = [];
            return expect(DateUtils.isValidModel(model)).to.be.false;
        });

        it("primitive model", function () {
            var model = 123;
            return expect(DateUtils.isValidModel(model)).to.be.false;
        });

        it("null datetime in model", function () {
            var model = {dt: null};
            return expect(DateUtils.isValidModel(model)).to.be.false;
        });

        it("infinity datetime", function () {
            var model = {dt: Infinity};
            return expect(DateUtils.isValidModel(model)).to.be.false;
        });

        it("string number datetime model", function () {
            var model = {dt: "123"};
            return expect(DateUtils.isValidModel(model)).to.be.true;
        });

        it("string datetime model", function () {
            var model = {dt: "some"};
            return expect(DateUtils.isValidModel(model)).to.be.false;
        });

        it("model dt is 0", function () {
            var model = {dt: 0};
            return expect(DateUtils.isValidModel(model)).to.be.true;
        });

    });

    describe("isDateUpperStartLimit", function () {

        it("datetime > start limit", function () {
            var dt = new Date(2015, 1, 2).getTime();
            var start = new Date(2015, 1, 1).getTime();

            return expect(DateUtils.isDateUpperStartLimit(dt, start)).to.be.true;
        });

        it("datetime < start limit", function () {
            var dt = new Date(2015, 1, 1).getTime();
            var start = new Date(2015, 1, 2).getTime();

            return expect(DateUtils.isDateUpperStartLimit(dt, start)).to.be.false;
        });

        it("datetime equal start limit", function () {
            var dt = new Date(2015, 1, 1).getTime();
            var start = new Date(2015, 1, 1).getTime();

            return expect(DateUtils.isDateUpperStartLimit(dt, start)).to.be.false;
        });

        it("no datetime", function () {
            var start = new Date(2015, 1, 1).getTime();

            //var spy = sinon.spy(DateUtils, 'isDateUpperStartLimit');
            return expect(function () {
                DateUtils.isDateUpperStartLimit(undefined, start);
            }).to.throw('NaN or null');
            //DateUtils.isDateUpperStartLimit.restore();
        });

        it("no start limit", function () {
            var dt = new Date(2015, 1, 1).getTime();
            return expect(DateUtils.isDateUpperStartLimit(dt, undefined)).to.be.true;
        });

        it("no args", function () {
            return expect(DateUtils.isDateUpperStartLimit()).to.be.true;
        });

        it("string args and datetime < start limit", function () {
            var dt = new Date(2015, 1, 1).getTime().toString();
            var start = new Date(2015, 1, 2).getTime().toString();

            return expect(DateUtils.isDateUpperStartLimit(dt, start)).to.be.false;
        });

        it("string args and datetime > start limit", function () {
            var dt = new Date(2015, 1, 2).getTime().toString();
            var start = new Date(2015, 1, 1).getTime().toString();

            return expect(DateUtils.isDateUpperStartLimit(dt, start)).to.be.true;
        });

        it("string args and datetime equal to start limit", function () {
            var dt = new Date(2015, 1, 1).getTime().toString();
            var start = new Date(2015, 1, 1).getTime().toString();

            return expect(DateUtils.isDateUpperStartLimit(dt, start)).to.be.false;
        });

        it("Infinity start", function () {
            var dt = new Date(2015, 1, 1).getTime();
            var start = Infinity;

            return expect(DateUtils.isDateUpperStartLimit(dt, start)).to.be.false;
        });

        it("Infinity datetime", function () {
            var dt = Infinity;
            var start = new Date(2015, 1, 1).getTime();

            return expect(DateUtils.isDateUpperStartLimit(dt, start)).to.be.true;
        });

        it("NaN datetime", function () {
            var dt = 'Adasdsd';
            var start = new Date(2015, 1, 1).getTime();

            //var spy = sinon.spy(DateUtils, 'isDateUpperStartLimit');
            return expect(function () {
                DateUtils.isDateUpperStartLimit(dt, start);
            }).to.throw('NaN or null');
            //DateUtils.isDateUpperStartLimit.restore();

        });

    });

    describe("isDateLowerEndLimit", function () {

        it("datetime > end limit", function () {
            var dt = new Date(2015, 1, 2).getTime();
            var end = new Date(2015, 1, 1).getTime();

            return expect(DateUtils.isDateLowerEndLimit(dt, end)).to.be.false;
        });

        it("datetime < end limit", function () {
            var dt = new Date(2015, 1, 1).getTime();
            var end = new Date(2015, 1, 2).getTime();

            return expect(DateUtils.isDateLowerEndLimit(dt, end)).to.be.true;
        });

        it("datetime equal end limit", function () {
            var dt = new Date(2015, 1, 1).getTime();
            var end = new Date(2015, 1, 1).getTime();

            return expect(DateUtils.isDateLowerEndLimit(dt, end)).to.be.false;
        });

        it("no datetime", function () {
            var end = new Date(2015, 1, 1).getTime();

            //var spy = sinon.spy(DateUtils, 'isDateLowerEndLimit');
            return expect(function () {
                DateUtils.isDateLowerEndLimit(undefined, end);
            }).to.throw('NaN or null');
            //DateUtils.isDateLowerEndLimit.restore();
        });

        it("no end limit", function () {
            var dt = new Date(2015, 1, 1).getTime();
            return expect(DateUtils.isDateLowerEndLimit(dt, undefined)).to.be.true;
        });

        it("no args", function () {
            return expect(DateUtils.isDateLowerEndLimit()).to.be.true;
        });

        it("string args and datetime < end limit", function () {
            var dt = new Date(2015, 1, 1).getTime().toString();
            var end = new Date(2015, 1, 2).getTime().toString();

            return expect(DateUtils.isDateLowerEndLimit(dt, end)).to.be.true;
        });

        it("string args and datetime > end limit", function () {
            var dt = new Date(2015, 1, 2).getTime().toString();
            var end = new Date(2015, 1, 1).getTime().toString();

            return expect(DateUtils.isDateLowerEndLimit(dt, end)).to.be.false;
        });

        it("string args and datetime equal to end limit", function () {
            var dt = new Date(2015, 1, 1).getTime().toString();
            var end = new Date(2015, 1, 1).getTime().toString();

            return expect(DateUtils.isDateLowerEndLimit(dt, end)).to.be.false;
        });

        it("Infinity end", function () {
            var dt = new Date(2015, 1, 1).getTime();
            var end = Infinity;

            return expect(DateUtils.isDateLowerEndLimit(dt, end)).to.be.true;
        });

        it("Infinity datetime", function () {
            var dt = Infinity;
            var end = new Date(2015, 1, 1).getTime();

            return expect(DateUtils.isDateLowerEndLimit(dt, end)).to.be.false;
        });

        it("NaN datetime", function () {
            var dt = 'Adasdsd';
            var end = new Date(2015, 1, 1).getTime();

            //var spy = sinon.spy(DateUtils, 'isDateLowerEndLimit');
            return expect(function () {
                DateUtils.isDateLowerEndLimit(dt, end);
            }).to.throw('NaN or null');
            //DateUtils.isDateLowerEndLimit.restore();

        });

    });

    describe("isDateBetweenLimits", function () {
        //TODO (S.Panfilov)
    });

    describe("getVal", function () {

        it("common case", function () {
            var datetime = new Date(2015, 1, 1).getTime();
            var method = Date.prototype.getDate;
            var result = new Date(datetime).getDate();

            expect(DateUtils._private.getVal(datetime, method)).to.be.equal(result);
        });

        it("not date method", function () {
            var datetime = new Date(2015, 1, 1).getTime();
            var expectVal = 123;
            var method = function () {
                return expectVal;
            };

            return expect(DateUtils._private.getVal(datetime, method)).to.be.equal(expectVal);
        });

        it("no method", function () {
            var datetime = new Date(2015, 1, 1).getTime();
            return expect(DateUtils._private.getVal(datetime)).to.be.null;
        });

        it("no date", function () {
            var method = Date.prototype.getDate;
            return expect(DateUtils._private.getVal(undefined, method)).to.be.NaN;
        });

        it("string num datetime", function () {
            var datetime = new Date(2015, 1, 1).getTime();
            var method = Date.prototype.getDate;
            var result = new Date(datetime).getDate();

            expect(DateUtils._private.getVal(datetime.toString(), method)).to.be.equal(result);
        });

        it("string datetime", function () {
            var method = Date.prototype.getDate;

            return expect(DateUtils._private.getVal(undefined, method)).to.be.NaN;
        });

        it("no args", function () {
            return expect(DateUtils._private.getVal()).to.be.null;
        });

    });
});<|endoftext|>


<commit_before>/* globals hopscotch: false */
/*
 * Elements courtesy of https://github.com/gthomas3
 * https://github.com/linkedin/hopscotch/issues/80#issuecomment-48330396
 */
function setCookie(key, value) {
    var expires = new Date();
    expires.setTime(expires.getTime() + (1 * 24 * 60 * 60 * 1000));
    document.cookie = key + '=' + value + ';path=/' + ';expires=' + expires.toUTCString();
}

function deleteCookie(key) {
    document.cookie = key + '=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;';
}

function getCookie(key) {
    var keyValue = document.cookie.match('(^|;) ?' + key + '=([^;]*)(;|$)');
    return keyValue ? keyValue[2] : null;
}

function isVisible(elem) {
    if (!(elem instanceof Element)) throw Error('DomUtil: elem is not an element.');
    const style = getComputedStyle(elem);
    if (style.display === 'none') return false;
    if (style.visibility !== 'visible') return false;
    if (style.opacity < 0.1) return false;
    if (elem.offsetWidth + elem.offsetHeight + elem.getBoundingClientRect().height +
        elem.getBoundingClientRect().width === 0) {
        return false;
    }
    const elemCenter   = {
        x: elem.getBoundingClientRect().left + elem.offsetWidth / 2,
        y: elem.getBoundingClientRect().top + elem.offsetHeight / 2
    };
    if (elemCenter.x < 0) return false;
    if (elemCenter.x > (document.documentElement.clientWidth || window.innerWidth)) return false;
    if (elemCenter.y < 0) return false;
    if (elemCenter.y > (document.documentElement.clientHeight || window.innerHeight)) return false;
    let pointContainer = document.elementFromPoint(elemCenter.x, elemCenter.y);
    do {
        if (pointContainer === elem) return true;
    } while (pointContainer = pointContainer.parentNode);
    return false;
}

function wrap(el, wrapper, newid) {
    wrapper.setAttribute("id", newid)
    el.parentNode.insertBefore(wrapper, el);
    wrapper.appendChild(el);
}

/*
var waitForElementVisible = function(element, callback) {
    var checkExist = setInterval(function() {
        $element = typeof element == "function" ? $(element()) : $(element);
        if ($element.is(':visible')) {
            clearInterval(checkExist);
            if (typeof callback == "function") {
                callback();
            }
        }
    }, 100);
};

var nextOnCallback = function(callback) {
    var currentStep = window.hopscotch.getCurrStepNum();
    callback(function() {
        window.hopscotch.startTour(theTour, currentStep);
    });
};
*/

var tour = {
    id: 'hello-cloudpak-for-multicloud-management',
    steps: [{
            target: document.querySelectorAll('.hamburger-box')[0],
            title: 'Hamburger Menu',
            content: 'Hey there! IBM is honored to be a partner in your journey with CP4MCM. There\'s plenty of time to read doc and sample code, but join us first on this quick feature fly-by!  This sidebar menu is your main navigation.',
            placement: 'right',
            arrowOffset: 0,
            onNext: ["openSideMenu"]
        },
        {
            target: { get target() { return '#overview' }},
            title: 'Overview',
            content: 'A great place to understand things at a very high level across all managed systems. Use the Overview page to view, manage, and reorganize the dashboard of your cluster information. You can view details of your clusters and other cloud service providers that IBM Multicloud Manager supports. You can also view details about your applications. The Overview dashboard is continuously refreshed in real time.',
            placement: 'right',
            arrowOffset: -20,
            delay: 500,
        },
        {
            target: { get target() { return '#topology' }},
            title: 'Topology View',
            content: 'Architects love this view. It visualizes relationships between components and within an application. With containerization, application boundaries may be hard to understand - but not with CP4MCM. The Topology page uses information from Weave Scope probe to display Kubernetes objects within a cluster. You can view hub cluster resources. As you configure managed clusters, you see more clusters in the Topology view.',
            placement: 'right',
            arrowOffset: 50,
        },
        {
            target: { get target() { return '#applications' }},
            title: 'Applications View',
            content: 'Developers and Operators appreciate this view. You can use the applications page to create, manage, view details, and troubleshoot application resources, including applications, deployables, channels, and subscriptions.',
            placement: 'right',
            arrowOffset: 150,
        },
    ],
    showPrevButton: true,
    scrollTopMargin: 100,
    onEnd: function() {
        setCookie("toured", "toured");
    }
    //onClose: function() {
    //    setCookie("toured", "toured");
    //}
};

/* ========== */
/* TOUR SETUP */
/* ========== */
var addClickListener = function(el, fn) {
    if (el.addEventListener) {
        el.addEventListener('click', fn, false);
    } else {
        el.attachEvent('onclick', fn);
    }
};

var init = function() {
    var startBtnId = 'startTourBtn',
        calloutId = 'startTourCallout',
        mgr = hopscotch.getCalloutManager(),
        state = hopscotch.getState();

    hopscotch.registerHelper("openSideMenu", function() {
        console.log("registerHelper invoked ...");
        document.querySelector('.hamburger-box').click();
        //var checkExist = setInterval(function() {
        //    var element = document.querySelectorAll('#overview')[0];
        //    if (element) {
        //      clearInterval(checkExist);
        console.log(document.querySelector('#overview').id);
        // Wrapping React element within a div to avoid Uncaught TypeError: j.getBoundingClientRect is not a function
        // https://github.com/soenkekluth/react-sticky-state/issues/9

        //wrap(document.querySelector('#overview'), document.createElement('div'), 'overview-tour');

        // window.hopscotch.startTour(window.hopscotch.getCurrTour(), window.hopscotch.getCurrStepNum());
        //    }
        //}, 2000);
    });

    if (state && state.indexOf('hello-cloudpak-for-multicloud-management') === 0) {
        // Already started the tour at some point!
        hopscotch.startTour(tour);
    } else {
        // Looking at the page for the first(?) time.
        if (!getCookie("toured")) {
            setTimeout(function() {
                mgr.createCallout({
                    id: calloutId,
                    target: startBtnId,
                    placement: 'bottom',
                    title: 'Friend, interested in a tour?',
                    content: 'We shall not cease from exploration
And the end of all our exploring
Will be to arrive where we started
And know the place for the first time.
∞T.S. Eliot∞',
                    yOffset: -25,
                    arrowOffset: 20,
                    width: 240
                });
            }, 100);
        }
    }

    addClickListener(document.getElementById(startBtnId), function() {
        if (!hopscotch.isActive) {
            mgr.removeAllCallouts();
            deleteCookie('toured');
            hopscotch.startTour(tour);
        }
    });

};

init();
<commit_msg>Updating MCM tour<commit_after>/* globals hopscotch: false */
/*
 * Elements courtesy of https://github.com/gthomas3
 * https://github.com/linkedin/hopscotch/issues/80#issuecomment-48330396
 */
function setCookie(key, value) {
    var expires = new Date();
    expires.setTime(expires.getTime() + (1 * 24 * 60 * 60 * 1000));
    document.cookie = key + '=' + value + ';path=/' + ';expires=' + expires.toUTCString();
}

function deleteCookie(key) {
    document.cookie = key + '=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;';
}

function getCookie(key) {
    var keyValue = document.cookie.match('(^|;) ?' + key + '=([^;]*)(;|$)');
    return keyValue ? keyValue[2] : null;
}

function isVisible(elem) {
    if (!(elem instanceof Element)) throw Error('DomUtil: elem is not an element.');
    const style = getComputedStyle(elem);
    if (style.display === 'none') return false;
    if (style.visibility !== 'visible') return false;
    if (style.opacity < 0.1) return false;
    if (elem.offsetWidth + elem.offsetHeight + elem.getBoundingClientRect().height +
        elem.getBoundingClientRect().width === 0) {
        return false;
    }
    const elemCenter   = {
        x: elem.getBoundingClientRect().left + elem.offsetWidth / 2,
        y: elem.getBoundingClientRect().top + elem.offsetHeight / 2
    };
    if (elemCenter.x < 0) return false;
    if (elemCenter.x > (document.documentElement.clientWidth || window.innerWidth)) return false;
    if (elemCenter.y < 0) return false;
    if (elemCenter.y > (document.documentElement.clientHeight || window.innerHeight)) return false;
    let pointContainer = document.elementFromPoint(elemCenter.x, elemCenter.y);
    do {
        if (pointContainer === elem) return true;
    } while (pointContainer = pointContainer.parentNode);
    return false;
}

function wrap(el, wrapper, newid) {
    wrapper.setAttribute("id", newid)
    el.parentNode.insertBefore(wrapper, el);
    wrapper.appendChild(el);
}

/*
var waitForElementVisible = function(element, callback) {
    var checkExist = setInterval(function() {
        $element = typeof element == "function" ? $(element()) : $(element);
        if ($element.is(':visible')) {
            clearInterval(checkExist);
            if (typeof callback == "function") {
                callback();
            }
        }
    }, 100);
};

var nextOnCallback = function(callback) {
    var currentStep = window.hopscotch.getCurrStepNum();
    callback(function() {
        window.hopscotch.startTour(theTour, currentStep);
    });
};
*/

var tour = {
    id: 'hello-cloudpak-for-multicloud-management',
    steps: [{
            target: document.querySelectorAll('.hamburger-box')[0],
            title: 'Hamburger Menu',
            content: 'Hey there! IBM is honored to be a partner in your journey with CP4MCM. There\'s plenty of time to read doc and sample code, but join us first on this quick feature fly-by!  This sidebar menu is your main navigation.',
            placement: 'right',
            arrowOffset: 0,
            onNext: ["openSideMenu"]
        },
        {
            target: { get target() { return '#overview' }},
            title: 'Overview',
            content: 'A great place to understand things at a very high level across all managed systems. Use the Overview page to view, manage, and reorganize the dashboard of your cluster information. You can view details of your clusters and other cloud service providers that IBM Multicloud Manager supports. You can also view details about your applications. The Overview dashboard is continuously refreshed in real time.',
            placement: 'right',
            arrowOffset: 0,
            delay: 500,
            onNext: ["openSideMenu"]
        },
        {
            target: { get target() { return '#topology' }},
            title: 'Topology Page',
            content: 'Architects love this view. It visualizes relationships between components and within an application. With containerization, application boundaries may be hard to understand - but not with CP4MCM. The Topology page uses information from Weave Scope probe to display Kubernetes objects within a cluster. You can view hub cluster resources. As you configure managed clusters, you see more clusters in the Topology view.',
            placement: 'right',
            arrowOffset: 0,
            delay: 500,
            onNext: ["openSideMenu"]
        },
        {
            target: { get target() { return '#applications' }},
            title: 'Applications Page',
            content: 'Developers and Operators appreciate this view. You can use the applications page to create, manage, view details, and troubleshoot application resources, including applications, deployables, channels, and subscriptions.',
            placement: 'right',
            arrowOffset: 50,
            delay: 500,
            onNext: ["openSideMenu"]
        },
        {
            target: '#search',
            title: 'Search Page',
            content: 'Operators need this view. The needs of one cluster rhyme with the needs of many. Find what you\'re looking for. There\'s alot to sift through.  With the search page, you get visibility into your resources across all your clusters. You can save your popular ones and the platform will happily suggest other filtered views for your consideration.',
            placement: 'right',
            arrowOffset: 50,
        },
    ],
    showPrevButton: true,
    scrollTopMargin: 100,
    onEnd: function() {
        setCookie("toured", "toured");
    }
    //onClose: function() {
    //    setCookie("toured", "toured");
    //}
};

/* ========== */
/* TOUR SETUP */
/* ========== */
var addClickListener = function(el, fn) {
    if (el.addEventListener) {
        el.addEventListener('click', fn, false);
    } else {
        el.attachEvent('onclick', fn);
    }
};

var init = function() {
    var startBtnId = 'startTourBtn',
        calloutId = 'startTourCallout',
        mgr = hopscotch.getCalloutManager(),
        state = hopscotch.getState();

    hopscotch.registerHelper("openSideMenu", function() {
        console.log("registerHelper invoked ...");
        document.querySelector('.hamburger-box').click();
        //var checkExist = setInterval(function() {
        //    var element = document.querySelectorAll('#overview')[0];
        //    if (element) {
        //      clearInterval(checkExist);
        console.log(document.querySelector('#overview').id);
        // Wrapping React element within a div to avoid Uncaught TypeError: j.getBoundingClientRect is not a function
        // https://github.com/soenkekluth/react-sticky-state/issues/9

        //wrap(document.querySelector('#overview'), document.createElement('div'), 'overview-tour');

        // window.hopscotch.startTour(window.hopscotch.getCurrTour(), window.hopscotch.getCurrStepNum());
        //    }
        //}, 2000);
    });

    if (state && state.indexOf('hello-cloudpak-for-multicloud-management') === 0) {
        // Already started the tour at some point!
        hopscotch.startTour(tour);
    } else {
        // Looking at the page for the first(?) time.
        if (!getCookie("toured")) {
            setTimeout(function() {
                mgr.createCallout({
                    id: calloutId,
                    target: startBtnId,
                    placement: 'bottom',
                    title: 'Friend, interested in a tour?',
                    content: 'We shall not cease from exploration
And the end of all our exploring
Will be to arrive where we started
And know the place for the first time.
∞T.S. Eliot∞',
                    yOffset: -25,
                    arrowOffset: 20,
                    width: 240
                });
            }, 100);
        }
    }

    addClickListener(document.getElementById(startBtnId), function() {
        if (!hopscotch.isActive) {
            mgr.removeAllCallouts();
            deleteCookie('toured');
            hopscotch.startTour(tour);
        }
    });

};

init();
<|endoftext|>


<commit_before>import {Pos} from "../model"
import {contains} from "../dom"
import {AssertionError} from "../util/error"

// : (ProseMirror, DOMNode) → [number]
// Get the path for a given a DOM node in a document.
export function pathFromDOM(pm, node) {
  let path = []
  for (; node != pm.content;) {
    let attr = node.getAttribute("pm-offset")
    if (attr) path.unshift(+attr)
    node = node.parentNode
  }
  return path
}

export function widthFromDOM(dom) {
  let attr = dom.getAttribute("pm-leaf")
  return attr && attr != "true" ? +attr : 1
}

export function posFromDOM(pm, dom, domOffset, loose) {
  if (!loose && pm.operation && pm.doc != pm.operation.doc)
    AssertionError.raise("Fetching a position from an outdated DOM structure")

  if (domOffset == null) {
    domOffset = Array.prototype.indexOf.call(dom.parentNode.childNodes, dom)
    dom = dom.parentNode
  }

  let extraOffset = 0, tag
  for (;;) {
    let adjust = 0
    if (dom.nodeType == 3) {
      extraOffset += domOffset
    } else if (dom.hasAttribute("pm-container")) {
      break
    } else if (tag = dom.getAttribute("pm-inner-offset")) {
      extraOffset += +tag
      adjust = -1
    } else if (domOffset && domOffset == dom.childNodes.length) {
      adjust = 1
    }

    let parent = dom.parentNode
    domOffset = adjust < 0 ? 0 : Array.prototype.indexOf.call(parent.childNodes, dom) + adjust
    dom = parent
  }

  let path = pathFromDOM(pm, dom)
  if (dom.hasAttribute("pm-leaf"))
    return Pos.from(path, extraOffset + (domOffset ? 1 : 0))

  let offset = 0
  for (let i = domOffset - 1; i >= 0; i--) {
    let child = dom.childNodes[i]
    if (child.nodeType == 3) {
      if (loose) extraOffset += child.nodeValue.length
    } else if (tag = child.getAttribute("pm-offset")) {
      offset = +tag + widthFromDOM(child)
      break
    } else if (loose && !child.hasAttribute("pm-ignore")) {
      extraOffset += child.textContent.length
    }
  }
  return new Pos(path, offset + extraOffset)
}

// : (DOMNode, number, ?bool)
// Get a child node of a parent node at a given offset.
export function findByPath(node, n, fromEnd) {
  let container = childContainer(node)
  for (let ch = fromEnd ? container.lastChild : container.firstChild; ch;
       ch = fromEnd ? ch.previousSibling : ch.nextSibling) {
    if (ch.nodeType != 1) continue
    let offset = ch.getAttribute("pm-offset")
    if (offset && +offset == n) return ch
  }
}

// : (DOMNode, [number]) → DOMNode
// Get a descendant node at a path relative to an ancestor node.
export function pathToDOM(parent, path) {
  let node = parent
  for (let i = 0; i < path.length; i++) {
    node = findByPath(node, path[i])
    if (!node) AssertionError.raise("Failed to resolve path " + path.join("/"))
  }
  return node
}

export function childContainer(dom) {
  return dom.hasAttribute("pm-container") ? dom : dom.querySelector("[pm-container]")
}

function findByOffset(node, offset, after) {
  for (let ch = node.firstChild, i = 0, attr; ch; ch = ch.nextSibling, i++) {
    if (ch.nodeType == 1 && (attr = ch.getAttribute("pm-offset"))) {
      let diff = offset - +attr, width = widthFromDOM(ch)
      if (diff >= 0 && (after ? diff <= width : diff < width))
        return {node: ch, offset: i, innerOffset: diff}
    }
  }
}

function leafAt(node, offset) {
  for (;;) {
    let child = node.firstChild
    if (!child) return {node, offset}
    if (child.nodeType != 1) return {node: child, offset}
    if (child.hasAttribute("pm-inner-offset")) {
      let nodeOffset = 0
      for (;;) {
        let nextSib = child.nextSibling, nextOffset
        if (!nextSib || (nextOffset = +nextSib.getAttribute("pm-inner-offset")) >= offset) break
        child = nextSib
        nodeOffset = nextOffset
      }
      offset -= nodeOffset
    }
    node = child
  }
}

// Get a DOM element at a given position in the document.
export function DOMFromPos(parent, pos) {
  let dom = childContainer(pathToDOM(parent, pos.path))
  let found = findByOffset(dom, pos.offset, true), inner
  if (!found) return {node: dom, offset: 0}
  if (found.node.getAttribute("pm-leaf") == "true" || !(inner = leafAt(found.node, found.innerOffset)))
    return {node: found.node.parentNode, offset: found.offset + (found.innerOffset ? 1 : 0)}
  else
    return inner
}

function windowRect() {
  return {left: 0, right: window.innerWidth,
          top: 0, bottom: window.innerHeight}
}

const scrollMargin = 5

export function scrollIntoView(pm, pos) {
  if (!pos) pos = pm.sel.range.head || pm.sel.range.from
  let coords = coordsAtPos(pm, pos)
  for (let parent = pm.content;; parent = parent.parentNode) {
    let atBody = parent == document.body
    let rect = atBody ? windowRect() : parent.getBoundingClientRect()
    let moveX = 0, moveY = 0
    if (coords.top < rect.top)
      moveY =  -(rect.top - coords.top + scrollMargin)
    else if (coords.bottom > rect.bottom)
      moveY = coords.bottom - rect.bottom + scrollMargin
    if (coords.left < rect.left)
      moveX = -(rect.left - coords.left + scrollMargin)
    else if (coords.right > rect.right)
      moveX = coords.right - rect.right + scrollMargin
    if (moveX || moveY) {
      if (atBody) window.scrollBy(moveX, moveY)
    } else {
      if (moveY) parent.scrollTop += moveY
      if (moveX) parent.scrollLeft += moveX
    }
    if (atBody) break
  }
}

function findOffsetInNode(node, coords) {
  let closest, dyClosest = 1e8, coordsClosest, offset = 0
  for (let child = node.firstChild; child; child = child.nextSibling) {
    let rects
    if (child.nodeType == 1) rects = child.getClientRects()
    else if (child.nodeType == 3) rects = textRects(child)
    else continue

    for (let i = 0; i < rects.length; i++) {
      let rect = rects[i]
      if (rect.left <= coords.left && rect.right >= coords.left) {
        let dy = rect.top > coords.top ? rect.top - coords.top
            : rect.bottom < coords.top ? coords.top - rect.bottom : 0
        if (dy < dyClosest) { // FIXME does not group by row
          closest = child
          dyClosest = dy
          coordsClosest = dy ? {left: coords.left, top: rect.top} : coords
          if (child.nodeType == 1 && !child.firstChild)
            offset = i + (coords.left >= (rect.left + rect.right) / 2 ? 1 : 0)
          continue
        }
      }
      if (!closest &&
          (coords.top >= rect.bottom || coords.top >= rect.top && coords.left >= rect.right))
        offset = i + 1
    }
  }
  if (!closest) return {node, offset}
  if (closest.nodeType == 3) return findOffsetInText(closest, coordsClosest)
  if (closest.firstChild) return findOffsetInNode(closest, coordsClosest)
  return {node, offset}
}

function findOffsetInText(node, coords) {
  let len = node.nodeValue.length
  let range = document.createRange()
  for (let i = 0; i < len; i++) {
    range.setEnd(node, i + 1)
    range.setStart(node, i)
    let rect = range.getBoundingClientRect()
    if (rect.top == rect.bottom) continue
    if (rect.left <= coords.left && rect.right >= coords.left &&
        rect.top <= coords.top && rect.bottom >= coords.top)
      return {node, offset: i + (coords.left >= (rect.left + rect.right) / 2 ? 1 : 0)}
  }
  return {node, offset: 0}
}

// Given an x,y position on the editor, get the position in the document.
export function posAtCoords(pm, coords) {
  let elt = document.elementFromPoint(coords.left, coords.top + 1)
  if (!contains(pm.content, elt)) return null

  if (!elt.firstChild) elt = elt.parentNode
  let {node, offset} = findOffsetInNode(elt, coords)
  return posFromDOM(pm, node, offset)
}

function textRect(node, from, to) {
  let range = document.createRange()
  range.setEnd(node, to)
  range.setStart(node, from)
  return range.getBoundingClientRect()
}

function textRects(node) {
  let range = document.createRange()
  range.setEnd(node, node.nodeValue.length)
  range.setStart(node, 0)
  return range.getClientRects()
}

// Given a position in the document model, get a bounding box of the character at
// that position, relative to the window.
export function coordsAtPos(pm, pos) {
  let {node, offset} = DOMFromPos(pm.content, pos)
  let side, rect
  if (node.nodeType == 3) {
    if (offset < node.nodeValue.length) {
      rect = textRect(node, offset, offset + 1)
      side = "left"
    }
    if ((!rect || rect.left == rect.right) && offset) {
      rect = textRect(node, offset - 1, offset)
      side = "right"
    }
  } else if (node.firstChild) {
    if (offset < node.childNodes.length) {
      let child = node.childNodes[offset]
      rect = child.nodeType == 3 ? textRect(child, 0, child.nodeValue.length) : child.getBoundingClientRect()
      side = "left"
    }
    if ((!rect || rect.left == rect.right) && offset) {
      let child = node.childNodes[offset - 1]
      rect = child.nodeType == 3 ? textRect(child, 0, child.nodeValue.length) : child.getBoundingClientRect()
      side = "right"
    }
  } else {
    rect = node.getBoundingClientRect()
    side = "left"
  }
  let x = rect[side]
  return {top: rect.top, bottom: rect.bottom, left: x, right: x}
}

export function setDOMSelectionToPos(pm, pos) {
  let {node, offset} = DOMFromPos(pm.content, pos)
  let range = document.createRange()
  range.setEnd(node, offset)
  range.setStart(node, offset)
  let sel = window.getSelection()
  sel.removeAllRanges()
  sel.addRange(range)
}

// ;; #path=NodeType #kind=class #noAnchor
// You can add several properties to [node types](#NodeType) to
// influence the way the editor interacts with them.

// :: (node: Node, path: [number], dom: DOMNode, coords: {left: number, top: number}) → ?Pos
// #path=NodeType.prototype.countCoordsAsChild
// Specifies that, if this node is clicked, a child node might
// actually be meant. This is used to, for example, make clicking a
// list marker (which, in the DOM, is part of the list node) select
// the list item it belongs to. Should return null if the given
// coordinates don't refer to a child node, or the [position](#Pos)
// before the child otherwise.

export function selectableNodeAbove(pm, dom, coords, liberal) {
  for (; dom && dom != pm.content; dom = dom.parentNode) {
    if (dom.hasAttribute("pm-offset")) {
      let path = pathFromDOM(pm, dom), node = pm.doc.path(path)
      if (node.type.countCoordsAsChild) {
        let result = node.type.countCoordsAsChild(node, path, dom, coords)
        if (result) return result
      }
      // Leaf nodes are implicitly clickable
      if ((liberal || node.type.contains == null) && node.type.selectable)
        return Pos.from(path)
      if (!liberal) return null
    }
  }
}

// :: (pm: ProseMirror, event: MouseEvent, path: [number], node: Node) → bool
// #path=NodeType.prototype.handleClick
// If a node is directly clicked (that is, the click didn't land in a
// DOM node belonging to a child node), and its type has a
// `handleClick` method, that method is given a chance to handle the
// click. The method is called, and should return `false` if it did
// _not_ handle the click.
//
// The `event` passed is the event for `"mousedown"`, but calling
// `preventDefault` on it has no effect, since this method is only
// called after a corresponding `"mouseup"` has occurred and
// ProseMirror has determined that this is not a drag or multi-click
// event.

// :: (pm: ProseMirror, event: MouseEvent, path: [number], node: Node) → bool
// #path=NodeType.prototype.handleContextMenu
//
// When the [context
// menu](https://developer.mozilla.org/en-US/docs/Web/Events/contextmenu)
// is activated in the editable context, nodes that the clicked
// position falls inside of get a chance to react to it. Node types
// may define a `handleContextMenu` method, which will be called when
// present, first on inner nodes and then up the document tree, until
// one of the methods returns something other than `false`.
//
// The handlers can inspect `event.target` to figure out whether they
// were directly clicked, and may call `event.preventDefault()` to
// prevent the native context menu.

export function handleNodeClick(pm, type, event, direct) {
  for (let dom = event.target; dom && dom != pm.content; dom = dom.parentNode) {
    if (dom.hasAttribute("pm-offset")) {
      let path = pathFromDOM(pm, dom), node = pm.doc.path(path)
      let handled = node.type[type] && node.type[type](pm, event, path, node) !== false
      if (direct || handled) return handled
    }
  }
}
<commit_msg>Fix double whitespace<commit_after>import {Pos} from "../model"
import {contains} from "../dom"
import {AssertionError} from "../util/error"

// : (ProseMirror, DOMNode) → [number]
// Get the path for a given a DOM node in a document.
export function pathFromDOM(pm, node) {
  let path = []
  for (; node != pm.content;) {
    let attr = node.getAttribute("pm-offset")
    if (attr) path.unshift(+attr)
    node = node.parentNode
  }
  return path
}

export function widthFromDOM(dom) {
  let attr = dom.getAttribute("pm-leaf")
  return attr && attr != "true" ? +attr : 1
}

export function posFromDOM(pm, dom, domOffset, loose) {
  if (!loose && pm.operation && pm.doc != pm.operation.doc)
    AssertionError.raise("Fetching a position from an outdated DOM structure")

  if (domOffset == null) {
    domOffset = Array.prototype.indexOf.call(dom.parentNode.childNodes, dom)
    dom = dom.parentNode
  }

  let extraOffset = 0, tag
  for (;;) {
    let adjust = 0
    if (dom.nodeType == 3) {
      extraOffset += domOffset
    } else if (dom.hasAttribute("pm-container")) {
      break
    } else if (tag = dom.getAttribute("pm-inner-offset")) {
      extraOffset += +tag
      adjust = -1
    } else if (domOffset && domOffset == dom.childNodes.length) {
      adjust = 1
    }

    let parent = dom.parentNode
    domOffset = adjust < 0 ? 0 : Array.prototype.indexOf.call(parent.childNodes, dom) + adjust
    dom = parent
  }

  let path = pathFromDOM(pm, dom)
  if (dom.hasAttribute("pm-leaf"))
    return Pos.from(path, extraOffset + (domOffset ? 1 : 0))

  let offset = 0
  for (let i = domOffset - 1; i >= 0; i--) {
    let child = dom.childNodes[i]
    if (child.nodeType == 3) {
      if (loose) extraOffset += child.nodeValue.length
    } else if (tag = child.getAttribute("pm-offset")) {
      offset = +tag + widthFromDOM(child)
      break
    } else if (loose && !child.hasAttribute("pm-ignore")) {
      extraOffset += child.textContent.length
    }
  }
  return new Pos(path, offset + extraOffset)
}

// : (DOMNode, number, ?bool)
// Get a child node of a parent node at a given offset.
export function findByPath(node, n, fromEnd) {
  let container = childContainer(node)
  for (let ch = fromEnd ? container.lastChild : container.firstChild; ch;
       ch = fromEnd ? ch.previousSibling : ch.nextSibling) {
    if (ch.nodeType != 1) continue
    let offset = ch.getAttribute("pm-offset")
    if (offset && +offset == n) return ch
  }
}

// : (DOMNode, [number]) → DOMNode
// Get a descendant node at a path relative to an ancestor node.
export function pathToDOM(parent, path) {
  let node = parent
  for (let i = 0; i < path.length; i++) {
    node = findByPath(node, path[i])
    if (!node) AssertionError.raise("Failed to resolve path " + path.join("/"))
  }
  return node
}

export function childContainer(dom) {
  return dom.hasAttribute("pm-container") ? dom : dom.querySelector("[pm-container]")
}

function findByOffset(node, offset, after) {
  for (let ch = node.firstChild, i = 0, attr; ch; ch = ch.nextSibling, i++) {
    if (ch.nodeType == 1 && (attr = ch.getAttribute("pm-offset"))) {
      let diff = offset - +attr, width = widthFromDOM(ch)
      if (diff >= 0 && (after ? diff <= width : diff < width))
        return {node: ch, offset: i, innerOffset: diff}
    }
  }
}

function leafAt(node, offset) {
  for (;;) {
    let child = node.firstChild
    if (!child) return {node, offset}
    if (child.nodeType != 1) return {node: child, offset}
    if (child.hasAttribute("pm-inner-offset")) {
      let nodeOffset = 0
      for (;;) {
        let nextSib = child.nextSibling, nextOffset
        if (!nextSib || (nextOffset = +nextSib.getAttribute("pm-inner-offset")) >= offset) break
        child = nextSib
        nodeOffset = nextOffset
      }
      offset -= nodeOffset
    }
    node = child
  }
}

// Get a DOM element at a given position in the document.
export function DOMFromPos(parent, pos) {
  let dom = childContainer(pathToDOM(parent, pos.path))
  let found = findByOffset(dom, pos.offset, true), inner
  if (!found) return {node: dom, offset: 0}
  if (found.node.getAttribute("pm-leaf") == "true" || !(inner = leafAt(found.node, found.innerOffset)))
    return {node: found.node.parentNode, offset: found.offset + (found.innerOffset ? 1 : 0)}
  else
    return inner
}

function windowRect() {
  return {left: 0, right: window.innerWidth,
          top: 0, bottom: window.innerHeight}
}

const scrollMargin = 5

export function scrollIntoView(pm, pos) {
  if (!pos) pos = pm.sel.range.head || pm.sel.range.from
  let coords = coordsAtPos(pm, pos)
  for (let parent = pm.content;; parent = parent.parentNode) {
    let atBody = parent == document.body
    let rect = atBody ? windowRect() : parent.getBoundingClientRect()
    let moveX = 0, moveY = 0
    if (coords.top < rect.top)
      moveY = -(rect.top - coords.top + scrollMargin)
    else if (coords.bottom > rect.bottom)
      moveY = coords.bottom - rect.bottom + scrollMargin
    if (coords.left < rect.left)
      moveX = -(rect.left - coords.left + scrollMargin)
    else if (coords.right > rect.right)
      moveX = coords.right - rect.right + scrollMargin
    if (moveX || moveY) {
      if (atBody) window.scrollBy(moveX, moveY)
    } else {
      if (moveY) parent.scrollTop += moveY
      if (moveX) parent.scrollLeft += moveX
    }
    if (atBody) break
  }
}

function findOffsetInNode(node, coords) {
  let closest, dyClosest = 1e8, coordsClosest, offset = 0
  for (let child = node.firstChild; child; child = child.nextSibling) {
    let rects
    if (child.nodeType == 1) rects = child.getClientRects()
    else if (child.nodeType == 3) rects = textRects(child)
    else continue

    for (let i = 0; i < rects.length; i++) {
      let rect = rects[i]
      if (rect.left <= coords.left && rect.right >= coords.left) {
        let dy = rect.top > coords.top ? rect.top - coords.top
            : rect.bottom < coords.top ? coords.top - rect.bottom : 0
        if (dy < dyClosest) { // FIXME does not group by row
          closest = child
          dyClosest = dy
          coordsClosest = dy ? {left: coords.left, top: rect.top} : coords
          if (child.nodeType == 1 && !child.firstChild)
            offset = i + (coords.left >= (rect.left + rect.right) / 2 ? 1 : 0)
          continue
        }
      }
      if (!closest &&
          (coords.top >= rect.bottom || coords.top >= rect.top && coords.left >= rect.right))
        offset = i + 1
    }
  }
  if (!closest) return {node, offset}
  if (closest.nodeType == 3) return findOffsetInText(closest, coordsClosest)
  if (closest.firstChild) return findOffsetInNode(closest, coordsClosest)
  return {node, offset}
}

function findOffsetInText(node, coords) {
  let len = node.nodeValue.length
  let range = document.createRange()
  for (let i = 0; i < len; i++) {
    range.setEnd(node, i + 1)
    range.setStart(node, i)
    let rect = range.getBoundingClientRect()
    if (rect.top == rect.bottom) continue
    if (rect.left <= coords.left && rect.right >= coords.left &&
        rect.top <= coords.top && rect.bottom >= coords.top)
      return {node, offset: i + (coords.left >= (rect.left + rect.right) / 2 ? 1 : 0)}
  }
  return {node, offset: 0}
}

// Given an x,y position on the editor, get the position in the document.
export function posAtCoords(pm, coords) {
  let elt = document.elementFromPoint(coords.left, coords.top + 1)
  if (!contains(pm.content, elt)) return null

  if (!elt.firstChild) elt = elt.parentNode
  let {node, offset} = findOffsetInNode(elt, coords)
  return posFromDOM(pm, node, offset)
}

function textRect(node, from, to) {
  let range = document.createRange()
  range.setEnd(node, to)
  range.setStart(node, from)
  return range.getBoundingClientRect()
}

function textRects(node) {
  let range = document.createRange()
  range.setEnd(node, node.nodeValue.length)
  range.setStart(node, 0)
  return range.getClientRects()
}

// Given a position in the document model, get a bounding box of the character at
// that position, relative to the window.
export function coordsAtPos(pm, pos) {
  let {node, offset} = DOMFromPos(pm.content, pos)
  let side, rect
  if (node.nodeType == 3) {
    if (offset < node.nodeValue.length) {
      rect = textRect(node, offset, offset + 1)
      side = "left"
    }
    if ((!rect || rect.left == rect.right) && offset) {
      rect = textRect(node, offset - 1, offset)
      side = "right"
    }
  } else if (node.firstChild) {
    if (offset < node.childNodes.length) {
      let child = node.childNodes[offset]
      rect = child.nodeType == 3 ? textRect(child, 0, child.nodeValue.length) : child.getBoundingClientRect()
      side = "left"
    }
    if ((!rect || rect.left == rect.right) && offset) {
      let child = node.childNodes[offset - 1]
      rect = child.nodeType == 3 ? textRect(child, 0, child.nodeValue.length) : child.getBoundingClientRect()
      side = "right"
    }
  } else {
    rect = node.getBoundingClientRect()
    side = "left"
  }
  let x = rect[side]
  return {top: rect.top, bottom: rect.bottom, left: x, right: x}
}

export function setDOMSelectionToPos(pm, pos) {
  let {node, offset} = DOMFromPos(pm.content, pos)
  let range = document.createRange()
  range.setEnd(node, offset)
  range.setStart(node, offset)
  let sel = window.getSelection()
  sel.removeAllRanges()
  sel.addRange(range)
}

// ;; #path=NodeType #kind=class #noAnchor
// You can add several properties to [node types](#NodeType) to
// influence the way the editor interacts with them.

// :: (node: Node, path: [number], dom: DOMNode, coords: {left: number, top: number}) → ?Pos
// #path=NodeType.prototype.countCoordsAsChild
// Specifies that, if this node is clicked, a child node might
// actually be meant. This is used to, for example, make clicking a
// list marker (which, in the DOM, is part of the list node) select
// the list item it belongs to. Should return null if the given
// coordinates don't refer to a child node, or the [position](#Pos)
// before the child otherwise.

export function selectableNodeAbove(pm, dom, coords, liberal) {
  for (; dom && dom != pm.content; dom = dom.parentNode) {
    if (dom.hasAttribute("pm-offset")) {
      let path = pathFromDOM(pm, dom), node = pm.doc.path(path)
      if (node.type.countCoordsAsChild) {
        let result = node.type.countCoordsAsChild(node, path, dom, coords)
        if (result) return result
      }
      // Leaf nodes are implicitly clickable
      if ((liberal || node.type.contains == null) && node.type.selectable)
        return Pos.from(path)
      if (!liberal) return null
    }
  }
}

// :: (pm: ProseMirror, event: MouseEvent, path: [number], node: Node) → bool
// #path=NodeType.prototype.handleClick
// If a node is directly clicked (that is, the click didn't land in a
// DOM node belonging to a child node), and its type has a
// `handleClick` method, that method is given a chance to handle the
// click. The method is called, and should return `false` if it did
// _not_ handle the click.
//
// The `event` passed is the event for `"mousedown"`, but calling
// `preventDefault` on it has no effect, since this method is only
// called after a corresponding `"mouseup"` has occurred and
// ProseMirror has determined that this is not a drag or multi-click
// event.

// :: (pm: ProseMirror, event: MouseEvent, path: [number], node: Node) → bool
// #path=NodeType.prototype.handleContextMenu
//
// When the [context
// menu](https://developer.mozilla.org/en-US/docs/Web/Events/contextmenu)
// is activated in the editable context, nodes that the clicked
// position falls inside of get a chance to react to it. Node types
// may define a `handleContextMenu` method, which will be called when
// present, first on inner nodes and then up the document tree, until
// one of the methods returns something other than `false`.
//
// The handlers can inspect `event.target` to figure out whether they
// were directly clicked, and may call `event.preventDefault()` to
// prevent the native context menu.

export function handleNodeClick(pm, type, event, direct) {
  for (let dom = event.target; dom && dom != pm.content; dom = dom.parentNode) {
    if (dom.hasAttribute("pm-offset")) {
      let path = pathFromDOM(pm, dom), node = pm.doc.path(path)
      let handled = node.type[type] && node.type[type](pm, event, path, node) !== false
      if (direct || handled) return handled
    }
  }
}
<|endoftext|>


<commit_before>import { select } from 'd3-selection'

export function ensureData(d, i) {
  if (!d) select(this).datum([])
}
<commit_msg>Fix stale data: Encapsulate initial pre-processed row cleanup.<commit_after>import { select } from 'd3-selection'

export function ensureData(d, i) {
  let rows = d || []
  rows.rows = null
  select(this).datum(rows)
}
<|endoftext|>