<commit_before>var signinCallback = function (json) {
    json = json || {};

    Backbone.GoogleAPIs.set("access_token", json["access_token"]);
    Backbone.GoogleAPIs.set("signed_in_user", json);

    _.defer(function() {
        $(".signed-out").hide();
        $(".signed-in").hide();

        var m = new Backbone.GoogleAPIs.UserInfo({});
        m.on("change", function() {
            var email = m.get("email");
            if (_.isEmpty(email)) {
                $(".signed-out").show().removeClass("hide");
                return;
            }

            $(".signed-in").show().removeClass("hide");
            $(".signed-in-email").html(email);

            var picture = m.get("picture");
            if (!_.isEmpty(picture)) $(".signed-in-picture").attr("src", picture);
        });
        m.on("error", function () {
            $(".signed-out").show().removeClass("hide");
        });
        m.fetch();
    });

    try {
        Backbone.history.start();
    } catch (e) {
        console.warn(e);
    }
};

// shared among File operations after insert
_.defer(function () {
    var App = Backbone.Router.extend({
        "__route": function (name, target_fn) {
            var wrapping_fn = function () {
                if (_.isFunction(target_fn)) _.defer(target_fn);
                if (!_.isUndefined(ChangeList) && _.isFunction(ChangeList.unpoll)) ChangeList.unpoll();

                $(".json-container").empty();
                $(".error-container").empty();

                // pretty printing target_fn
                var strFn = "" + target_fn;
                var clnFn = _.map(strFn.split("\n"), function(line) {
                    return line.replace("        ", "");
                });
                $(".code-container").html(clnFn.join("\n"));

                var auxparts = [];
                if (strFn.indexOf("displayJson") >= 0) auxparts.push("var displayJson = " + displayJson + ";");
                if (strFn.indexOf("displayError") >= 0) auxparts.push("var displayError = " + displayError + ";");
                $(".aux-code-container").html(auxparts.join("\n\n"));
            };

            this.route(name, name, wrapping_fn);
        }
    });

    app = new App();

    // resets buckets inputs
    app.on("route", function (href) {
        if (_.isEqual(href, "list-buckets")) {
            $(".list-buckets-inputs").show().removeClass("hide");
        } else {
            $(".list-buckets-inputs").hide();
        }
        $(".buckets-needs-project-id").hide();
    });
    // resets comments inputs
    app.on("route", function (href) {
        if (_.isEqual(href, "plus-list-comments")) {
            $(".list-comments-inputs").show().removeClass("hide");
        } else {
            $(".list-comments-inputs").hide();
        }
        $(".list-comments-needs-activity-id").hide();
    });
    // toggles active list item
    app.on("route", function (href) {
        _.each($(".top-level-anchors").find("a.list-group-item"), function (item) {
            $(item).removeClass("active");
            if (_.isEqual($(item).attr("href"), "#" + href)) $(item).addClass("active");
        });
    });

    // configures buttons for controlling model instantiation strategy
    var readyRoutes = function(e) {
        var modelTypeSelector = localStorage.getItem("modeltype-selector") || "model-factory";

        $(".btn-modeltype-selector").removeClass("active btn-success");
        _.each($(".btn-modeltype-selector"), function(e) {
            var newType = $(e).data("type");
            if (newType === modelTypeSelector) $(e).addClass("active btn-success");
        });

        var demoFnRoutes = ["about", "userinfo", "list-apps", "list-folders", "list-changes", "list-buckets",
            "file-insert", "file-fetch", "file-update", "file-touch", "file-trash", "file-untrash", "file-empty-trash",
            "plus-get-person", "plus-list-people", "plus-list-activity", "plus-list-moments", "plus-list-comments"];
        _.each(demoFnRoutes, function(demoFnRoute) {
            var fn = DemoFns[modelTypeSelector][demoFnRoute] || DemoFns["neither"][demoFnRoute];
            if (_.isFunction(fn)) app.__route(demoFnRoute, fn);
        });
    };

    $(".btn-modeltype-selector").on("click", function(e) {
        localStorage.setItem("modeltype-selector", $(e.target).data("type"));
        _.defer(readyRoutes);
        _.defer(function() {
            Backbone.history.loadUrl(Backbone.history.fragment)
        });
    });

    $(".ls-vars-activate").on("click", function() {
        $(".aux-vars-container").html(JSON.stringify(localStorage, undefined, 2));
    });

    // change to HTTPS
    app.route("goto-https", "goto-https", function() {
        var loca = document["location"];
        document["location"] = "https:" + (loca["host"] || loca["hostname"]) + loca["pathname"];
    });
    if (document.location.protocol === "https:") {
        $(".goto-https-container").hide();
    }

    app.__route("sign-out", function() {
        if (_.isEmpty(Backbone.GoogleAPIs.get("access_token"))) {
            document.location = document.location.href.replace("#sign-out", "");
            return;
        }

        var po = document.createElement("script");
        po["type"] = "text/javascript";
        po["async"] = true;
        po["src"] = "https://accounts.google.com/o/oauth2/revoke?token=" + Backbone.GoogleAPIs.get("access_token");
        po["onload"] = function () {
            document.location = document.location.href.replace("#sign-out", "");
        };

        var s = document.getElementsByTagName("script")[0];
        s["parentNode"].insertBefore(po, s);
    });

    _.defer(readyRoutes);
});

// displays JS dependencies
_.defer(function () {
    _.each($("script"), function (script) {
        if (script && _.has(script, "src")) {
            if (script["src"].indexOf("chrome-extension") >= 0) return;
            if (script["src"].indexOf("apps-static") >= 0) return;
            $(".deps-container").append("
" + script["src"] + "
");
        }
    });
});
<commit_msg>removing comment<commit_after>var signinCallback = function (json) {
    json = json || {};

    Backbone.GoogleAPIs.set("access_token", json["access_token"]);
    Backbone.GoogleAPIs.set("signed_in_user", json);

    _.defer(function() {
        $(".signed-out").hide();
        $(".signed-in").hide();

        var m = new Backbone.GoogleAPIs.UserInfo({});
        m.on("change", function() {
            var email = m.get("email");
            if (_.isEmpty(email)) {
                $(".signed-out").show().removeClass("hide");
                return;
            }

            $(".signed-in").show().removeClass("hide");
            $(".signed-in-email").html(email);

            var picture = m.get("picture");
            if (!_.isEmpty(picture)) $(".signed-in-picture").attr("src", picture);
        });
        m.on("error", function () {
            $(".signed-out").show().removeClass("hide");
        });
        m.fetch();
    });

    try {
        Backbone.history.start();
    } catch (e) {
        console.warn(e);
    }
};

_.defer(function () {
    var App = Backbone.Router.extend({
        "__route": function (name, target_fn) {
            var wrapping_fn = function () {
                if (_.isFunction(target_fn)) _.defer(target_fn);
                if (!_.isUndefined(ChangeList) && _.isFunction(ChangeList.unpoll)) ChangeList.unpoll();

                $(".json-container").empty();
                $(".error-container").empty();

                // pretty printing target_fn
                var strFn = "" + target_fn;
                var clnFn = _.map(strFn.split("\n"), function(line) {
                    return line.replace("        ", "");
                });
                $(".code-container").html(clnFn.join("\n"));

                var auxparts = [];
                if (strFn.indexOf("displayJson") >= 0) auxparts.push("var displayJson = " + displayJson + ";");
                if (strFn.indexOf("displayError") >= 0) auxparts.push("var displayError = " + displayError + ";");
                $(".aux-code-container").html(auxparts.join("\n\n"));
            };

            this.route(name, name, wrapping_fn);
        }
    });

    app = new App();

    // resets buckets inputs
    app.on("route", function (href) {
        if (_.isEqual(href, "list-buckets")) {
            $(".list-buckets-inputs").show().removeClass("hide");
        } else {
            $(".list-buckets-inputs").hide();
        }
        $(".buckets-needs-project-id").hide();
    });
    // resets comments inputs
    app.on("route", function (href) {
        if (_.isEqual(href, "plus-list-comments")) {
            $(".list-comments-inputs").show().removeClass("hide");
        } else {
            $(".list-comments-inputs").hide();
        }
        $(".list-comments-needs-activity-id").hide();
    });
    // toggles active list item
    app.on("route", function (href) {
        _.each($(".top-level-anchors").find("a.list-group-item"), function (item) {
            $(item).removeClass("active");
            if (_.isEqual($(item).attr("href"), "#" + href)) $(item).addClass("active");
        });
    });

    // configures buttons for controlling model instantiation strategy
    var readyRoutes = function(e) {
        var modelTypeSelector = localStorage.getItem("modeltype-selector") || "model-factory";

        $(".btn-modeltype-selector").removeClass("active btn-success");
        _.each($(".btn-modeltype-selector"), function(e) {
            var newType = $(e).data("type");
            if (newType === modelTypeSelector) $(e).addClass("active btn-success");
        });

        var demoFnRoutes = ["about", "userinfo", "list-apps", "list-folders", "list-changes", "list-buckets",
            "file-insert", "file-fetch", "file-update", "file-touch", "file-trash", "file-untrash", "file-empty-trash",
            "plus-get-person", "plus-list-people", "plus-list-activity", "plus-list-moments", "plus-list-comments"];
        _.each(demoFnRoutes, function(demoFnRoute) {
            var fn = DemoFns[modelTypeSelector][demoFnRoute] || DemoFns["neither"][demoFnRoute];
            if (_.isFunction(fn)) app.__route(demoFnRoute, fn);
        });
    };

    $(".btn-modeltype-selector").on("click", function(e) {
        localStorage.setItem("modeltype-selector", $(e.target).data("type"));
        _.defer(readyRoutes);
        _.defer(function() {
            Backbone.history.loadUrl(Backbone.history.fragment)
        });
    });

    $(".ls-vars-activate").on("click", function() {
        $(".aux-vars-container").html(JSON.stringify(localStorage, undefined, 2));
    });

    // change to HTTPS
    app.route("goto-https", "goto-https", function() {
        var loca = document["location"];
        document["location"] = "https:" + (loca["host"] || loca["hostname"]) + loca["pathname"];
    });
    if (document.location.protocol === "https:") {
        $(".goto-https-container").hide();
    }

    app.__route("sign-out", function() {
        if (_.isEmpty(Backbone.GoogleAPIs.get("access_token"))) {
            document.location = document.location.href.replace("#sign-out", "");
            return;
        }

        var po = document.createElement("script");
        po["type"] = "text/javascript";
        po["async"] = true;
        po["src"] = "https://accounts.google.com/o/oauth2/revoke?token=" + Backbone.GoogleAPIs.get("access_token");
        po["onload"] = function () {
            document.location = document.location.href.replace("#sign-out", "");
        };

        var s = document.getElementsByTagName("script")[0];
        s["parentNode"].insertBefore(po, s);
    });

    _.defer(readyRoutes);
});

// displays JS dependencies
_.defer(function () {
    _.each($("script"), function (script) {
        if (script && _.has(script, "src")) {
            if (script["src"].indexOf("chrome-extension") >= 0) return;
            if (script["src"].indexOf("apps-static") >= 0) return;
            $(".deps-container").append("
" + script["src"] + "
");
        }
    });
});
<|endoftext|>


<commit_before>// # Demo Canvas 002
// Block and wheel entity positioning (start, pivot, mimic, mouse)

// [Run code](../../demo/canvas-002.html)
import scrawl from '../source/scrawl.js'

import { reportSpeed, killArtefact } from './utilities.js';

// Get Scrawl-canvas to recognise and act on device pixel ratios greater than 1
scrawl.setIgnorePixelRatio(false);

// #### Scene setup
let canvas = scrawl.library.artefact.mycanvas;

canvas.setBase({
    clearAlpha: 0.9,
    // backgroundColor: 'aliceblue',
});

// Create and clone block and wheel entitys. For the sake of safety and sanity, create the (reference) entitys on which other artefacts will pivot and mimic first. Then create those other artefacts.
//
// Note: setting this entity's `method` value to __none__ means that while it will perform all necessary calculations as part of the Display cycle, it will not complete its stamp action, thus will not appear on the display. This differs from setting its `visibility` attribute to false, which will make the entity skip both calculation and stamp operations
let myPivot = scrawl.makeWheel({
    name: 'mouse-pivot',
    method: 'none',

    startX: 'center',
    startY: 'center',
});

let myblock = scrawl.makeBlock({
    name: 'base-block',

    width: 150,
    height: 100,

    handleX: 'center',
    handleY: 'center',

    offsetX: -140,
    offsetY: -50,

    // To pivot this entity to the reference entity, we need to set both its `pivot` attribute (to the reference entity's name, or the entity itself) __and also__ set the `lockTo` attribute to the value __'pivot'__
    pivot: 'mouse-pivot',
    lockTo: 'pivot',

    fillStyle: 'darkblue',
    strokeStyle: 'gold',
    method: 'fillAndDraw',

    lineWidth: 6,
    lineJoin: 'round',

    delta: {
        roll: 0.5,
    },
});

let mywheel = scrawl.makeWheel({
    name: 'base-wheel',

    radius: 60,
    startAngle: 35,
    endAngle: -35,

    handleX: 'center',
    handleY: 'center',

    offsetX: 140,
    offsetY: 50,

    pivot: 'mouse-pivot',
    lockTo: 'pivot',

    fillStyle: 'purple',
    strokeStyle: 'gold',
    method: 'fillAndDraw',

    lineWidth: 6,
    lineJoin: 'round',

    delta: {
        roll: -0.5,
    },
});

myblock.clone({
    name: 'pivot-block',

    height: 30,

    handleX: 'center',
    handleY: 'center',

    strokeStyle: 'red',
    lineWidth: 3,
    method: 'draw',

    pivot: 'base-block',
    lockTo: 'pivot',

    offsetX: 0,
    offsetY: 110,
    addPivotOffset: true,

    delta: {
        roll: 0,
    },

}).clone({
    name: 'pivot-wheel',

    pivot: 'base-wheel',
    addPivotRotation: true,

    handleX: 0,
    handleY: '50%',

    offsetY: 0,

}).clone({
    name: 'mimic-wheel',

    // `mimic` is an extended form of `pivot`
    mimic: 'base-wheel',
    lockTo: 'mimic',

    // When an entity mimics another entity's dimensions, its own dimensions (width, height) can be added to the mimic dimensions
    width: 20,
    height: 20,

    // Handles can be directly affected by mimic dimensions. If the entity adds its own dimensions to the mimics dimensions, then it may also need to add appropriate handle values to the mimic's handle
    handleX: 10,
    handleY: 10,

    strokeStyle: 'darkgreen',

    // The default values for the __useMimic__ and __addOwn__ variables is 'false' - including false attributes here only for convenience during development work
    useMimicDimensions: true,
    useMimicScale: true,
    useMimicStart: true,
    useMimicHandle: true,
    useMimicOffset: true,
    useMimicRotation: true,
    useMimicFlip: true,

    addOwnDimensionsToMimic: true,
    addOwnScaleToMimic: false,
    addOwnStartToMimic: false,
    addOwnHandleToMimic: true,
    addOwnOffsetToMimic: false,
    addOwnRotationToMimic: false,
});

mywheel.clone({
    name: 'mimic-block',

    mimic: 'base-block',
    lockTo: 'mimic',

    width: 60,

    strokeStyle: 'darkgreen',
    lineWidth: 3,
    method: 'draw',

    useMimicDimensions: true,
    useMimicScale: true,
    useMimicStart: true,
    useMimicOffset: true,
    useMimicRotation: true,
    addOwnDimensionsToMimic: true,
});

// #### User interaction
// Function to check whether mouse cursor is over canvas, and lock the reference entity accordingly
let mouseCheck = function () {

    let active = false;

    return function () {

        if (canvas.here.active !== active) {

            active = canvas.here.active;

            myPivot.set({
                lockTo: (active) ? 'mouse' : 'start'
            });
        }
    };
}();

// Setup form observer functionality.
scrawl.observeAndUpdate({

    event: ['input', 'change'],
    origin: '.controlItem',

    target: canvas.base,

    useNativeListener: true,
    preventDefault: true,

    updates: {

        backgroundColor: ['backgroundColor', 'raw'],
        clearAlpha: ['clearAlpha', 'float'],
    },
});

const backgroundColorSelector = document.querySelector('#backgroundColor'),
    clearAlphaInput = document.querySelector('#clearAlpha');

backgroundColorSelector.value = '';
clearAlphaInput.value = 0.9;

// #### Scene animation
// Function to display frames-per-second data, and other information relevant to the demo
const report = reportSpeed('#reportmessage', function () {
    return `    clearAlpha: ${clearAlphaInput.value}`;
});

// Create the Display cycle animation
scrawl.makeRender({

    name: 'demo-animation',
    target: canvas,
    commence: mouseCheck,
    afterShow: report,
});

// #### Development and testing
console.log(scrawl.library);

// console.log('Performing tests ...');

// killArtefact(canvas, 'mouse-pivot', 4000, () => {

//     myPivot = scrawl.library.entity['mouse-pivot'];

//     scrawl.library.entity['base-block'].set({

//         pivot: myPivot,
//         lockTo: 'pivot',
//     });

//     scrawl.library.entity['base-wheel'].set({

//         pivot: myPivot,
//         lockTo: 'pivot',
//     });
// });

// killArtefact(canvas, 'mimic-block', 6000);
<commit_msg>clearcell bugfix for Safari<commit_after>// # Demo Canvas 002
// Block and wheel entity positioning (start, pivot, mimic, mouse)

// [Run code](../../demo/canvas-002.html)
import scrawl from '../source/scrawl.js'

import { reportSpeed, killArtefact } from './utilities.js';

// Get Scrawl-canvas to recognise and act on device pixel ratios greater than 1
scrawl.setIgnorePixelRatio(false);

// #### Scene setup
let canvas = scrawl.library.artefact.mycanvas;

canvas.setBase({
    clearAlpha: 0.9,
});

// Create and clone block and wheel entitys. For the sake of safety and sanity, create the (reference) entitys on which other artefacts will pivot and mimic first. Then create those other artefacts.
//
// Note: setting this entity's `method` value to __none__ means that while it will perform all necessary calculations as part of the Display cycle, it will not complete its stamp action, thus will not appear on the display. This differs from setting its `visibility` attribute to false, which will make the entity skip both calculation and stamp operations
let myPivot = scrawl.makeWheel({
    name: 'mouse-pivot',
    method: 'none',

    startX: 'center',
    startY: 'center',
});

let myblock = scrawl.makeBlock({
    name: 'base-block',

    width: 150,
    height: 100,

    handleX: 'center',
    handleY: 'center',

    offsetX: -140,
    offsetY: -50,

    // To pivot this entity to the reference entity, we need to set both its `pivot` attribute (to the reference entity's name, or the entity itself) __and also__ set the `lockTo` attribute to the value __'pivot'__
    pivot: 'mouse-pivot',
    lockTo: 'pivot',

    fillStyle: 'darkblue',
    strokeStyle: 'gold',
    method: 'fillAndDraw',

    lineWidth: 6,
    lineJoin: 'round',

    delta: {
        roll: 0.5,
    },
});

let mywheel = scrawl.makeWheel({
    name: 'base-wheel',

    radius: 60,
    startAngle: 35,
    endAngle: -35,

    handleX: 'center',
    handleY: 'center',

    offsetX: 140,
    offsetY: 50,

    pivot: 'mouse-pivot',
    lockTo: 'pivot',

    fillStyle: 'purple',
    strokeStyle: 'gold',
    method: 'fillAndDraw',

    lineWidth: 6,
    lineJoin: 'round',

    delta: {
        roll: -0.5,
    },
});

myblock.clone({
    name: 'pivot-block',

    height: 30,

    handleX: 'center',
    handleY: 'center',

    strokeStyle: 'red',
    lineWidth: 3,
    method: 'draw',

    pivot: 'base-block',
    lockTo: 'pivot',

    offsetX: 0,
    offsetY: 110,
    addPivotOffset: true,

    delta: {
        roll: 0,
    },

}).clone({
    name: 'pivot-wheel',

    pivot: 'base-wheel',
    addPivotRotation: true,

    handleX: 0,
    handleY: '50%',

    offsetY: 0,

}).clone({
    name: 'mimic-wheel',

    // `mimic` is an extended form of `pivot`
    mimic: 'base-wheel',
    lockTo: 'mimic',

    // When an entity mimics another entity's dimensions, its own dimensions (width, height) can be added to the mimic dimensions
    width: 20,
    height: 20,

    // Handles can be directly affected by mimic dimensions. If the entity adds its own dimensions to the mimics dimensions, then it may also need to add appropriate handle values to the mimic's handle
    handleX: 10,
    handleY: 10,

    strokeStyle: 'darkgreen',

    // The default values for the __useMimic__ and __addOwn__ variables is 'false' - including false attributes here only for convenience during development work
    useMimicDimensions: true,
    useMimicScale: true,
    useMimicStart: true,
    useMimicHandle: true,
    useMimicOffset: true,
    useMimicRotation: true,
    useMimicFlip: true,

    addOwnDimensionsToMimic: true,
    addOwnScaleToMimic: false,
    addOwnStartToMimic: false,
    addOwnHandleToMimic: true,
    addOwnOffsetToMimic: false,
    addOwnRotationToMimic: false,
});

mywheel.clone({
    name: 'mimic-block',

    mimic: 'base-block',
    lockTo: 'mimic',

    width: 60,

    strokeStyle: 'darkgreen',
    lineWidth: 3,
    method: 'draw',

    useMimicDimensions: true,
    useMimicScale: true,
    useMimicStart: true,
    useMimicOffset: true,
    useMimicRotation: true,
    addOwnDimensionsToMimic: true,
});

// #### User interaction
// Function to check whether mouse cursor is over canvas, and lock the reference entity accordingly
let mouseCheck = function () {

    let active = false;

    return function () {

        if (canvas.here.active !== active) {

            active = canvas.here.active;

            myPivot.set({
                lockTo: (active) ? 'mouse' : 'start'
            });
        }
    };
}();

// Setup form observer functionality.
scrawl.observeAndUpdate({

    event: ['input', 'change'],
    origin: '.controlItem',

    target: canvas.base,

    useNativeListener: true,
    preventDefault: true,

    updates: {

        backgroundColor: ['backgroundColor', 'raw'],
        clearAlpha: ['clearAlpha', 'float'],
    },
});

const backgroundColorSelector = document.querySelector('#backgroundColor'),
    clearAlphaInput = document.querySelector('#clearAlpha');

backgroundColorSelector.value = '';
clearAlphaInput.value = 0.9;

// #### Scene animation
// Function to display frames-per-second data, and other information relevant to the demo
const report = reportSpeed('#reportmessage', function () {
    return `    clearAlpha: ${clearAlphaInput.value}`;
});

// Create the Display cycle animation
scrawl.makeRender({

    name: 'demo-animation',
    target: canvas,
    commence: mouseCheck,
    afterShow: report,
});

// #### Development and testing
console.log(scrawl.library);

console.log('Performing tests ...');

killArtefact(canvas, 'mouse-pivot', 4000, () => {

    myPivot = scrawl.library.entity['mouse-pivot'];

    scrawl.library.entity['base-block'].set({

        pivot: myPivot,
        lockTo: 'pivot',
    });

    scrawl.library.entity['base-wheel'].set({

        pivot: myPivot,
        lockTo: 'pivot',
    });
});

killArtefact(canvas, 'mimic-block', 6000);
<|endoftext|>


<commit_before>/* autogenerated by the update_version script */
exports.version=1518644400;
<commit_msg>new version -- the user-api<commit_after>/* autogenerated by the update_version script */
exports.version=1518655864;
<|endoftext|>


<commit_before><commit_msg>Easy configuration of TURN server and forced relaying<commit_after><|endoftext|>


<commit_before>// @flow

import fs from "fs-promise"
import path from "path"

import debug from "debug"

import urlAsHtml from "./url-as-html"
import routesToUrls from "../routes-to-urls"
import urlify from "../../_utils/urlify"
import * as pagesActions from "../../redux/modules/pages"

if (pagesActions.SET === undefined) {
  throw new Error("pages SET action is undefined")
}
if (pagesActions.FORGET === undefined) {
  throw new Error("pages FORGET action is undefined")
}

const log = debug("phenomic:static:to-html")

export function setPageData(
  url: string,
  collection: PhenomicCollection,
  store: Object
): void {
  const json = collection.find((item) => item.__url === url)
  if (!json) {
    log(`No json in for url '${ url }'.`)
  }
  else {
    // prepare page data
    store.dispatch({
      type: pagesActions.SET,
      page: url,
      response: { json },
    })
  }
}

export function forgetPageData(
  url: string,
  store: Object
): void {
  // forget page data to avoid having all pages data in all
  // pages
  store.dispatch({
    type: pagesActions.FORGET,
    page: url,
  })
}

export function writeHTMLFile(
  filename: string,
  html: string
): Promise<string> {
  return fs.mkdirs(path.dirname(filename))
    .then(() => Promise.all([
      fs.writeFile(filename, html),
    ]))
    .then(() => filename)
}

export function writeAllHTMLFiles(
  {
    baseUrl,
    destination,
    assetsFiles,
    metadata,
    routes,
    store,
    collection,
    setPageData,
    forgetPageData,
    writeHTMLFile,
    offline,
    offlineConfig,
  }: {
    baseUrl: Object,
    destination: string,
    assetsFiles: Object,
    metadata: Object,
    routes: Object,
    store: Object,
    collection: PhenomicCollection,
    setPageData: Function,
    forgetPageData: Function,
    writeHTMLFile: Function,
    offline: boolean,
    offlineConfig: PhenomicOfflineConfig,
  },
  testing?: boolean
): Promise<Array<void>> {
  const urls = routesToUrls(routes, collection)

  // create all html files
  return Promise.all(
    urls.map((url) => {
      const item = collection.find((item) => item.__url === url)
      const filename = item
        ? path.join(destination, item.__resourceUrl)
        : path.join(destination, urlify(url, true))

      setPageData(url, collection, store)
      return (
        urlAsHtml(url, {
          metadata,
          routes,
          store,
          collection,

          baseUrl,
          assetsFiles,
          offline,
          offlineConfig,
        }, testing)
        .then((html) => writeHTMLFile(filename, html))
        .then(() => forgetPageData(url, store))
      )
    })
  )
}

export default
function(options: Object, testing?: boolean): Promise<Array<void>> {
  return writeAllHTMLFiles({
    ...options,
    setPageData,
    forgetPageData,
    writeHTMLFile,
  }, testing)
}
<commit_msg>Remove "No json in url" log entry (#638)<commit_after>// @flow

import fs from "fs-promise"
import path from "path"

import urlAsHtml from "./url-as-html"
import routesToUrls from "../routes-to-urls"
import urlify from "../../_utils/urlify"
import * as pagesActions from "../../redux/modules/pages"

if (pagesActions.SET === undefined) {
  throw new Error("pages SET action is undefined")
}
if (pagesActions.FORGET === undefined) {
  throw new Error("pages FORGET action is undefined")
}

export function setPageData(
  url: string,
  collection: PhenomicCollection,
  store: Object
): void {
  const json = collection.find((item) => item.__url === url)
  if (json) {
    // prepare page data
    store.dispatch({
      type: pagesActions.SET,
      page: url,
      response: { json },
    })
  }
}

export function forgetPageData(
  url: string,
  store: Object
): void {
  // forget page data to avoid having all pages data in all pages
  store.dispatch({
    type: pagesActions.FORGET,
    page: url,
  })
}

export function writeHTMLFile(
  filename: string,
  html: string
): Promise<string> {
  return fs.mkdirs(path.dirname(filename))
    .then(() => Promise.all([
      fs.writeFile(filename, html),
    ]))
    .then(() => filename)
}

export function writeAllHTMLFiles(
  {
    baseUrl,
    destination,
    assetsFiles,
    metadata,
    routes,
    store,
    collection,
    setPageData,
    forgetPageData,
    writeHTMLFile,
    offline,
    offlineConfig,
  }: {
    baseUrl: Object,
    destination: string,
    assetsFiles: Object,
    metadata: Object,
    routes: Object,
    store: Object,
    collection: PhenomicCollection,
    setPageData: Function,
    forgetPageData: Function,
    writeHTMLFile: Function,
    offline: boolean,
    offlineConfig: PhenomicOfflineConfig,
  },
  testing?: boolean
): Promise<Array<void>> {
  const urls = routesToUrls(routes, collection)

  // create all html files
  return Promise.all(
    urls.map((url) => {
      const item = collection.find((item) => item.__url === url)
      const filename = item
        ? path.join(destination, item.__resourceUrl)
        : path.join(destination, urlify(url, true))

      setPageData(url, collection, store)
      return (
        urlAsHtml(url, {
          metadata,
          routes,
          store,
          collection,

          baseUrl,
          assetsFiles,
          offline,
          offlineConfig,
        }, testing)
        .then((html) => writeHTMLFile(filename, html))
        .then(() => forgetPageData(url, store))
      )
    })
  )
}

export default
function(options: Object, testing?: boolean): Promise<Array<void>> {
  return writeAllHTMLFiles({
    ...options,
    setPageData,
    forgetPageData,
    writeHTMLFile,
  }, testing)
}
<|endoftext|>


<commit_before>import { autorun, action, observable, computed, toJS } from 'mobx';
import { isUndefined, omitBy } from 'lodash';
import ModalStore from 'stores/ModalStore';
import BaseDataStore from 'stores/BaseDataStore';
import parseColumn from 'utils/parseColumn';

export default class DataListStore extends BaseDataStore {
	@observable isFetching = false;
	@observable selectedKeys = [];
	@observable query = {};
	@observable queryFieldsCount = 0;

	collections = observable.map();
	totals = observable.map();

	@computed
	get cacheKey() {
		return JSON.stringify(toJS(this.query));
	}

	@computed
	get collection() {
		return this.collections.get(this.cacheKey);
	}

	@computed
	get total() {
		return this.totals.get(this.cacheKey) || 0;
	}

	@computed
	get dataSource() {
		return toJS(this.collection);
	}

	@computed
	get sortedKey() {
		return this.query[this.appConfig.api.sortKey];
	}

	@computed
	get sortedOrder() {
		const { orderKey, ascValue } = this.appConfig.api;
		let order = this.query[orderKey];

		if (!this.sortedKey) {
			return order;
		}

		/* eslint-disable eqeqeq */
		return order == ascValue ? 'ascend' : 'descend';
	}

	@computed
	get columns() {
		const { renderers } = this.config;
		if (!renderers) return [];
		return renderers.map(({ renderTable: renderCell, props }) => {
			const column = parseColumn({
				title: props.label,
				key: props.name,
				dataIndex: props.name,
				headers: { renderCell },
				body: (state) => ({
					store: { text: state.value, ...state },
					renderCell,
				}),
			});
			if (props.sortable) {
				const { sortedKey, sortedOrder } = this;
				column.sortOrder = props.name === sortedKey ? sortedOrder : false;
				column.sorter = true;
			}
			return column;
		});
	}

	get maxSelections() {
		return this.config.maxSelections;
	}

	get renderers() {
		return this.config.renderers;
	}

	constructor(options) {
		super(options);

		const { config, appConfig, baseRequest } = this;
		const { api } = config;

		this.size = +appConfig.api.count;
		this.extends = {};

		if (api) {
			this.uniqueKey = config.uniqueKey;
			const count = +api.query.count;
			const hasCount = !!count;

			if (hasCount) {
				this.size = count;
			}

			const request = baseRequest.clone({
				queryTransformer: (query) => {
					if (hasCount) query.count = count;
					return query;
				},
			});
			this.performRequest = request.fetch.bind(request);
		}
	}

	addQueryListener(routerStore) {
		if (routerStore && routerStore.location) {
			this.query = routerStore.location.query;
			this._routerStore = routerStore;
		}
		this._hasBoundQueryListener = false;
		const disposer = autorun(() => {
			if (this.query && !this._hasBoundQueryListener) {
				this._hasBoundQueryListener = true;
			} else {
				// fetch trick
				setTimeout(() => {
					this.fetch({ query: this.query });
				});
			}
		});
		return function removeQueryListener() {
			this._routerStore = null;
			return disposer();
		};
	}

	async setQuery(query) {
		if (this._routerStore) {
			this._routerStore.location.query = query;
		} else {
			this.query = query;
		}
	}

	async fetch(options = {}) {
		const { query, method, url, body, headers } = options;
		const { cacheKey } = this;

		if (this.collections.has(cacheKey)) {
			return this;
		}

		this.isFetching = true;

		const fetchOptions = {
			method,
			url,
			body,
			headers,
			query: {
				count: this.size,
				...omitBy(query, ModalStore.getOmitPaths),
				page: (function () {
					const p = (query && query.page) || 1;
					return p < 1 ? 1 : p;
				})(),
			},
		};

		const res = await this.request({
			...omitBy(fetchOptions, isUndefined),
			refresh: false,
		});

		const requestRes = await this.config.mapOnFetchResponse(res);
		const { total, list = [] } = requestRes || {};

		const collection = list.map((data, index) => {
			data.key = this.uniqueKey ? data[this.uniqueKey] : index;
			return data;
		});

		this.collections.set(cacheKey, collection);
		this.totals.set(cacheKey, total);
		this.isFetching = false;
		return this;
	}

	@action
	refresh() {
		this.collections.clear();
		this.totals.clear();
		this.fetch({ query: this.query });
		this.selectedKeys = [];
	}

	@action
	increaseQueryFieldsCount() {
		this.queryFieldsCount++;
	}

	@action
	decreaseQueryFieldsCount() {
		this.queryFieldsCount--;
	}

	setSelectedKeys(selectedKeys = []) {
		this.selectedKeys = selectedKeys;
	}

	clearSelectedKeys() {
		this.selectedKeys = [];
	}

	getData(key) {
		const { collection, uniqueKey, selectedKeys } = this;
		if (isUndefined(key)) {
			key = selectedKeys[0];
		}
		if (isUndefined(key) || !collection) {
			return null;
		}
		return collection.find(
			(dataItem, index) => key === (uniqueKey ? dataItem[uniqueKey] : index)
		);
	}
}
<commit_msg>fix DataListStore extends bug<commit_after>import { autorun, action, observable, computed, toJS } from 'mobx';
import { isUndefined, omitBy } from 'lodash';
import ModalStore from 'stores/ModalStore';
import BaseDataStore from 'stores/BaseDataStore';
import parseColumn from 'utils/parseColumn';

export default class DataListStore extends BaseDataStore {
	@observable isFetching = false;
	@observable selectedKeys = [];
	@observable query = {};
	@observable queryFieldsCount = 0;

	collections = observable.map();
	totals = observable.map();

	@computed
	get cacheKey() {
		return JSON.stringify(toJS(this.query));
	}

	@computed
	get collection() {
		return this.collections.get(this.cacheKey);
	}

	@computed
	get total() {
		return this.totals.get(this.cacheKey) || 0;
	}

	@computed
	get dataSource() {
		return toJS(this.collection);
	}

	@computed
	get sortedKey() {
		return this.query[this.appConfig.api.sortKey];
	}

	@computed
	get sortedOrder() {
		const { orderKey, ascValue } = this.appConfig.api;
		let order = this.query[orderKey];

		if (!this.sortedKey) {
			return order;
		}

		/* eslint-disable eqeqeq */
		return order == ascValue ? 'ascend' : 'descend';
	}

	@computed
	get columns() {
		const { renderers } = this.config;
		if (!renderers) return [];
		return renderers.map(({ renderTable: renderCell, props }) => {
			const column = parseColumn({
				title: props.label,
				key: props.name,
				dataIndex: props.name,
				headers: { renderCell },
				body: (state) => ({
					store: { text: state.value, ...state },
					renderCell,
				}),
			});
			if (props.sortable) {
				const { sortedKey, sortedOrder } = this;
				column.sortOrder = props.name === sortedKey ? sortedOrder : false;
				column.sorter = true;
			}
			return column;
		});
	}

	get maxSelections() {
		return this.config.maxSelections;
	}

	get renderers() {
		return this.config.renderers;
	}

	constructor(options) {
		super(options);

		const { config, appConfig, baseRequest } = this;
		const { api } = config;

		this.size = +appConfig.api.count;

		if (api) {
			this.uniqueKey = config.uniqueKey;
			const count = +api.query.count;
			const hasCount = !!count;

			if (hasCount) {
				this.size = count;
			}

			const request = baseRequest.clone({
				queryTransformer: (query) => {
					if (hasCount) query.count = count;
					return query;
				},
			});
			this.performRequest = request.fetch.bind(request);
		}
	}

	addQueryListener(routerStore) {
		if (routerStore && routerStore.location) {
			this.query = routerStore.location.query;
			this._routerStore = routerStore;
		}
		this._hasBoundQueryListener = false;
		const disposer = autorun(() => {
			if (this.query && !this._hasBoundQueryListener) {
				this._hasBoundQueryListener = true;
			} else {
				// fetch trick
				setTimeout(() => {
					this.fetch({ query: this.query });
				});
			}
		});
		return function removeQueryListener() {
			this._routerStore = null;
			return disposer();
		};
	}

	async setQuery(query) {
		if (this._routerStore) {
			this._routerStore.location.query = query;
		} else {
			this.query = query;
		}
	}

	async fetch(options = {}) {
		const { query, method, url, body, headers } = options;
		const { cacheKey } = this;

		if (this.collections.has(cacheKey)) {
			return this;
		}

		this.isFetching = true;

		const fetchOptions = {
			method,
			url,
			body,
			headers,
			query: {
				count: this.size,
				...omitBy(query, ModalStore.getOmitPaths),
				page: (function () {
					const p = (query && query.page) || 1;
					return p < 1 ? 1 : p;
				})(),
			},
		};

		const res = await this.request({
			...omitBy(fetchOptions, isUndefined),
			refresh: false,
		});

		const requestRes = await this.config.mapOnFetchResponse(res);
		const { total, list = [] } = requestRes || {};

		const collection = list.map((data, index) => {
			data.key = this.uniqueKey ? data[this.uniqueKey] : index;
			return data;
		});

		this.collections.set(cacheKey, collection);
		this.totals.set(cacheKey, total);
		this.isFetching = false;
		return this;
	}

	@action
	refresh() {
		this.collections.clear();
		this.totals.clear();
		this.fetch({ query: this.query });
		this.selectedKeys = [];
	}

	@action
	increaseQueryFieldsCount() {
		this.queryFieldsCount++;
	}

	@action
	decreaseQueryFieldsCount() {
		this.queryFieldsCount--;
	}

	setSelectedKeys(selectedKeys = []) {
		this.selectedKeys = selectedKeys;
	}

	clearSelectedKeys() {
		this.selectedKeys = [];
	}

	getData(key) {
		const { collection, uniqueKey, selectedKeys } = this;
		if (isUndefined(key)) {
			key = selectedKeys[0];
		}
		if (isUndefined(key) || !collection) {
			return null;
		}
		return collection.find(
			(dataItem, index) => key === (uniqueKey ? dataItem[uniqueKey] : index)
		);
	}
}
<|endoftext|>


<commit_before>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * All rights reserved.
 */

/**
 * @name CharacterStyle
 *
 * @class The CharacterStyle object represents the character style of a text
 * item ({@link TextItem#characterStyle})
 *
 * @extends PathStyle
 *
 * @classexample
 * var text = new PointText(new Point(50, 50));
 * text.content = 'Hello world.';
 * text.characterStyle = {
 * 	fontSize: 50,
 * 	fillColor: 'black',
 * };
 */
var CharacterStyle = this.CharacterStyle = PathStyle.extend(/** @lends CharacterStyle# */{
	_defaults: Base.merge(PathStyle.prototype._defaults, {
		// Override default fillColor of CharacterStyle
		fillColor: 'black',
		fontSize: 10,
		leading: null,
		font: 'sans-serif'
	}),
	_owner: TextItem,
	_style: '_characterStyle'

	/**
	 * CharacterStyle objects don't need to be created directly. Just pass an
	 * object to {@link TextItem#characterStyle}, it will be converted to a
	 * CharacterStyle object internally.
	 *
	 * @name CharacterStyle#initialize
	 * @param {object} style
	 */

	/**
	 * The font of the character style.
	 *
	 * @name CharacterStyle#font
	 * @default 'sans-serif'
	 * @type String
	 */

	/**
	 * The font size of the character style in points.
	 *
	 * @name CharacterStyle#fontSize
	 * @default 10
	 * @type Number
	 */
}, {
	getLeading: function() {
		// Override leading to return fontSize * 1.2 by default, when undefined
		var leading = this.base();
		return leading != null ? leading : this.getFontSize() * 1.2;
	}
});
<commit_msg>Increase default type size to 12px.<commit_after>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * All rights reserved.
 */

/**
 * @name CharacterStyle
 *
 * @class The CharacterStyle object represents the character style of a text
 * item ({@link TextItem#characterStyle})
 *
 * @extends PathStyle
 *
 * @classexample
 * var text = new PointText(new Point(50, 50));
 * text.content = 'Hello world.';
 * text.characterStyle = {
 * 	fontSize: 50,
 * 	fillColor: 'black',
 * };
 */
var CharacterStyle = this.CharacterStyle = PathStyle.extend(/** @lends CharacterStyle# */{
	_defaults: Base.merge(PathStyle.prototype._defaults, {
		// Override default fillColor of CharacterStyle
		fillColor: 'black',
		fontSize: 12,
		leading: null,
		font: 'sans-serif'
	}),
	_owner: TextItem,
	_style: '_characterStyle'

	/**
	 * CharacterStyle objects don't need to be created directly. Just pass an
	 * object to {@link TextItem#characterStyle}, it will be converted to a
	 * CharacterStyle object internally.
	 *
	 * @name CharacterStyle#initialize
	 * @param {object} style
	 */

	/**
	 * The font of the character style.
	 *
	 * @name CharacterStyle#font
	 * @default 'sans-serif'
	 * @type String
	 */

	/**
	 * The font size of the character style in points.
	 *
	 * @name CharacterStyle#fontSize
	 * @default 10
	 * @type Number
	 */
}, {
	getLeading: function() {
		// Override leading to return fontSize * 1.2 by default, when undefined
		var leading = this.base();
		return leading != null ? leading : this.getFontSize() * 1.2;
	}
});
<|endoftext|>


<commit_before>"use strict";

window.cls || (window.cls = {});

/**
 * @constructor
 */
cls.ElementLayout = function()
{
  this._es_debugger = window.services['ecmascript-debugger'];
  this._tag_manager = cls.TagManager.get_instance();
  this._stylesheets = window.stylesheets;
  this._css_index_map = null;
  this._selected_element = null;
  this._comp_style = null;
  this._offset_values = "";
  this._views = ['css-layout'];

  var OFFSET_TOP = 1;
  var OFFSET_LEFT = 2;
  var OFFSET_WIDTH = 3;
  var OFFSET_HEIGHT = 4;
  var SCROLL_TOP = 5;
  var SCROLL_LEFT = 6;
  var SCROLL_WIDTH = 7;
  var SCROLL_HEIGHT = 8;
  var CLIENT_TOP = 9;
  var CLIENT_LEFT = 10;
  var CLIENT_WIDTH = 11;
  var CLIENT_HEIGHT = 12;
  var OFFSETS = cls.ElementLayout.OFFSETS;
  var OFFSETS_SCRIPT = "\
    (function(ele)\
    {\
      var \
      parent = ele,\
      log = ele.nodeName + '|0;',\
      offsetParent = ele.offsetParent,\
      offsets =\
      [\
        '" + OFFSETS[OFFSET_TOP] + "',\
        '" + OFFSETS[OFFSET_LEFT] + "',\
        '" + OFFSETS[OFFSET_WIDTH] + "',\
        '" + OFFSETS[OFFSET_HEIGHT] + "',\
        '" + OFFSETS[SCROLL_TOP] + "',\
        '" + OFFSETS[SCROLL_LEFT] + "',\
        '" + OFFSETS[SCROLL_WIDTH] + "',\
        '" + OFFSETS[SCROLL_HEIGHT] + "',\
        '" + OFFSETS[CLIENT_TOP] + "',\
        '" + OFFSETS[CLIENT_LEFT] + "',\
        '" + OFFSETS[CLIENT_WIDTH] + "',\
        '" + OFFSETS[CLIENT_HEIGHT] + "'\
      ],\
      offset = '',\
      i = 0;\
      while ((parent = parent.parentNode) && parent.nodeType == 1)\
      {\
        if (parent == offsetParent)\
        {\
          log = parent.nodeName + '|1,' + log;\
          offsetParent = parent.offsetParent;\
        }\
        else\
        {\
          log = parent.nodeName + '|0,' + log;\
        }\
      };\
      for ( ; offset = offsets[i]; i++)\
      {\
        log += ele[offset] + ';';\
      }\
      return log;\
    })(ele)\
    ";

  this._on_element_selected = function(msg)
  {
    this._comp_style = null;
    this._offset_values = "";
    this._selected_element = msg.rt_id && msg.obj_id
                           ? {rt_id: msg.rt_id,
                              obj_id: msg.obj_id,
                              model: msg.model}
                           : null;

    for (var i = 0, view_id; view_id = this._views[i]; i++)
    {
      window.views[view_id].update();
    }
  };

  this.has_selected_element = function()
  {
    return Boolean(this._selected_element);
  };

  this.get_layout_values = function(callback)
  {
    if (!this._selected_element)
    {
      callback(null);
      return;
    }

    if (this._comp_style)
    {
      callback(this._comp_style);
      return;
    }

    var rt_id = this._selected_element.rt_id;
    var obj_id = this._selected_element.obj_id;

    if (this._stylesheets.has_stylesheets_runtime(rt_id))
    {
      var tag = this._tag_manager.set_callback(this, this._handle_get_metrics_data, [rt_id, obj_id, callback]);
      this._es_debugger.requestCssGetStyleDeclarations(tag, [rt_id, obj_id]);
    }
    else
    {
      this._stylesheets.get_stylesheets(this._selected_element.rt_id, this.get_layout_values.bind(this, callback));
    }
  };

  this._handle_get_metrics_data = function(status, message, rt_id, obj_id, callback, index_map)
  {
    var COMPUTED_STYLE_LIST = 0;
    var NODE_STYLE_LIST = 1;

    this._comp_style = message[COMPUTED_STYLE_LIST];
    if (!this._css_index_map)
    {
      if (!index_map)
      {
        window.stylesheets.get_css_index_map(this._handle_get_metrics_data.bind(this, status, message, rt_id, obj_id, callback));
        return;
      }
      else
      {
        this._css_index_map = index_map;
      }
    }

    if (callback)
      callback(this._comp_style);
  };

  this.get_offset_values = function(cb)
  {
    if (!this._selected_element)
    {
      cb(null);
    }
    else if (this._offset_values)
    {
      cb(window.helpers.copy_object(this._offset_values));
    }
    else
    {
      var rt_id = this._selected_element.rt_id;
      var obj_id = this._selected_element.obj_id;
      var tag = this._tag_manager.set_callback(null, this._handle_get_offset_data_bound, [rt_id, obj_id, cb]);
      this._es_debugger.requestEval(tag, [rt_id, 0, 0, OFFSETS_SCRIPT, [['ele', obj_id]]]);
    }
  };

  this._handle_get_offset_data = function(status, message, rt_id, obj_id, cb)
  {
    var STATUS = 0;
    var VALUE = 2;
    if (message[STATUS] == 'completed')
    {
      this._offset_values = this._parse_offset_values(message[VALUE]);
      if (cb)
        cb(window.helpers.copy_object(this._offset_values));
    }
    else
    {
      opera.postError(ui_strings.S_DRAGONFLY_INFO_MESSAGE +
        '_handle_get_offset_data failed')
    }
  };

  this._handle_get_offset_data_bound = this._handle_get_offset_data.bind(this);

  this._parse_offset_values = function(offset_values)
  {
    var data = offset_values.slice(0, -1).split(';'); // Remove the last ';' before splitting
    data[0] = data[0].split(',').map(function(item){
      return item.split('|');
    });
    return data;
  }

  this.get_metrics_template = function(comp_style)
  {
    var index_map = this._css_index_map;
    var is_positioned = comp_style[index_map.indexOf("position")] != "static";
    return (
      ['div',
        ['ul',
          ['li',
            ['ul',
              ['li',
                ['p',
                  '\u00A0',
                  ['span',
                    is_positioned
                    ? 'position'
                    : '\u00A0'
                  ]
                ]
              ],
              ['li',
                is_positioned
                ? this._convert_to_unitless(comp_style[index_map.indexOf("top")])
                : '\u00A0'
              ],
              ['li']
            ],
            ['ul',
              ['li',
                is_positioned
                ? this._convert_to_unitless(comp_style[index_map.indexOf("left")])
                : '\u00A0'
              ],
              ['li',
                ['ul',
                  ['li',
                    ['p',
                      '\u00a0',
                      ['span',
                        'margin'
                      ]
                    ]
                  ],
                  ['li',
                    this._convert_to_unitless(comp_style[index_map.indexOf("margin-top")])
                  ],
                  ['li']
                ],
                ['ul',
                  ['li',
                    this._convert_to_unitless(comp_style[index_map.indexOf("margin-left")])
                  ],
                  ['li',
                    ['ul',
                      ['li',
                        ['p',
                          '\u00a0',
                          ['span',
                            'border'
                          ]
                        ]
                      ],
                      ['li',
                        this._convert_to_unitless(comp_style[index_map.indexOf("border-top-width")])
                      ],
                      ['li']
                    ],
                    ['ul',
                      ['li',
                        this._convert_to_unitless(comp_style[index_map.indexOf("border-left-width")])
                      ],
                      ['li',
                        ['ul',
                          ['li',
                            ['p',
                              '\u00a0',
                              ['span',
                                'padding'
                              ]
                            ]
                          ],
                          ['li',
                            this._convert_to_unitless(comp_style[index_map.indexOf("padding-top")])
                          ],
                          ['li']
                        ],
                        ['ul',
                          ['li',
                            this._convert_to_unitless(comp_style[index_map.indexOf("padding-left")])
                          ],
                          ['li',
                            ['ul',
                              ['li',
                                '\u00a0'
                              ]
                            ],
                            ['ul',
                              ['li',
                                this._convert_to_unitless(comp_style[index_map.indexOf("width")], true) +
                                ' × ' +
                                this._convert_to_unitless(comp_style[index_map.indexOf("height")], true)
                              ]
                            ],
                            ['ul',
                              ['li',
                                '\u00a0'
                              ]
                            ],
                           'class', 'dimension'
                          ],
                          ['li',
                            this._convert_to_unitless(comp_style[index_map.indexOf("padding-right")])
                          ]
                        ],
                        ['ul',
                          ['li'],
                          ['li',
                            this._convert_to_unitless(comp_style[index_map.indexOf("padding-bottom")])
                          ],
                          ['li']
                        ],
                      'class', 'padding'
                      ],
                      ['li',
                        this._convert_to_unitless(comp_style[index_map.indexOf("border-right-width")])
                      ]
                    ],
                    ['ul',
                      ['li'],
                      ['li',
                        this._convert_to_unitless(comp_style[index_map.indexOf("border-bottom-width")])
                      ],
                      ['li']
                    ],
                   'class', 'border'
                  ],
                  ['li',
                    this._convert_to_unitless(comp_style[index_map.indexOf("margin-right")])
                  ]
                ],
                ['ul',
                  ['li'],
                  ['li',
                    this._convert_to_unitless(comp_style[index_map.indexOf("margin-bottom")])
                  ],
                  ['li']
                ],
               'class', 'margin'
              ],
              ['li',
                is_positioned
                ? this._convert_to_unitless(comp_style[index_map.indexOf("right")])
                : '\u00A0'
              ]
            ],
            ['ul',
              ['li'],
              ['li',
                is_positioned
                ? this._convert_to_unitless(comp_style[index_map.indexOf("bottom")])
                : '\u00A0'
              ],
              ['li']
            ],
           'class', is_positioned ? 'position' : ''
          ],
         'class', comp_style[index_map.indexOf("box-sizing")]
        ],
        ['table',
          ['tr',
            ['th',
              'position:'
            ],
            ['td',
              comp_style[index_map.indexOf("position")] || "–"
            ],
           'data-spec', 'css#position'
          ],
          ['tr',
            ['th',
              'z-index:'
            ],
            ['td',
              comp_style[index_map.indexOf("z-index")] || "–"
            ],
           'data-spec', 'css#z-index'
          ],
          ['tr',
            ['th',
              'box-sizing:'
            ],
            ['td',
              comp_style[index_map.indexOf("box-sizing")] || "–"
            ],
           'data-spec', 'css#box-sizing'
          ],
         'id', 'layout-info'
        ]
      ]
    );
  };

  this._convert_to_unitless = function(value, no_replace)
  {
    switch (value)
    {
    case "auto":
      return value;
    case "0px":
      return no_replace ? "0" : "–";
    case "":
      return "–";
    default:
      return String(parseInt(value))
    }
  };

  window.messages.addListener('element-selected', this._on_element_selected.bind(this));
};

cls.ElementLayout.OFFSETS = [
  '',
  'offsetTop',
  'offsetLeft',
  'offsetWidth',
  'offsetHeight',
  'scrollTop',
  'scrollLeft',
  'scrollWidth',
  'scrollHeight',
  'clientTop',
  'clientLeft',
  'clientWidth',
  'clientHeight'
];

<commit_msg>Fixed Bitbucket issue #143: layout tab is confusing for elements with box-sizing: border-box.<commit_after>"use strict";

window.cls || (window.cls = {});

/**
 * @constructor
 */
cls.ElementLayout = function()
{
  this._es_debugger = window.services['ecmascript-debugger'];
  this._tag_manager = cls.TagManager.get_instance();
  this._stylesheets = window.stylesheets;
  this._css_index_map = null;
  this._selected_element = null;
  this._comp_style = null;
  this._offset_values = "";
  this._views = ['css-layout'];

  var OFFSET_TOP = 1;
  var OFFSET_LEFT = 2;
  var OFFSET_WIDTH = 3;
  var OFFSET_HEIGHT = 4;
  var SCROLL_TOP = 5;
  var SCROLL_LEFT = 6;
  var SCROLL_WIDTH = 7;
  var SCROLL_HEIGHT = 8;
  var CLIENT_TOP = 9;
  var CLIENT_LEFT = 10;
  var CLIENT_WIDTH = 11;
  var CLIENT_HEIGHT = 12;
  var OFFSETS = cls.ElementLayout.OFFSETS;
  var OFFSETS_SCRIPT = "\
    (function(ele)\
    {\
      var \
      parent = ele,\
      log = ele.nodeName + '|0;',\
      offsetParent = ele.offsetParent,\
      offsets =\
      [\
        '" + OFFSETS[OFFSET_TOP] + "',\
        '" + OFFSETS[OFFSET_LEFT] + "',\
        '" + OFFSETS[OFFSET_WIDTH] + "',\
        '" + OFFSETS[OFFSET_HEIGHT] + "',\
        '" + OFFSETS[SCROLL_TOP] + "',\
        '" + OFFSETS[SCROLL_LEFT] + "',\
        '" + OFFSETS[SCROLL_WIDTH] + "',\
        '" + OFFSETS[SCROLL_HEIGHT] + "',\
        '" + OFFSETS[CLIENT_TOP] + "',\
        '" + OFFSETS[CLIENT_LEFT] + "',\
        '" + OFFSETS[CLIENT_WIDTH] + "',\
        '" + OFFSETS[CLIENT_HEIGHT] + "'\
      ],\
      offset = '',\
      i = 0;\
      while ((parent = parent.parentNode) && parent.nodeType == 1)\
      {\
        if (parent == offsetParent)\
        {\
          log = parent.nodeName + '|1,' + log;\
          offsetParent = parent.offsetParent;\
        }\
        else\
        {\
          log = parent.nodeName + '|0,' + log;\
        }\
      };\
      for ( ; offset = offsets[i]; i++)\
      {\
        log += ele[offset] + ';';\
      }\
      return log;\
    })(ele)\
    ";

  this._on_element_selected = function(msg)
  {
    this._comp_style = null;
    this._offset_values = "";
    this._selected_element = msg.rt_id && msg.obj_id
                           ? {rt_id: msg.rt_id,
                              obj_id: msg.obj_id,
                              model: msg.model}
                           : null;

    for (var i = 0, view_id; view_id = this._views[i]; i++)
    {
      window.views[view_id].update();
    }
  };

  this.has_selected_element = function()
  {
    return Boolean(this._selected_element);
  };

  this.get_layout_values = function(callback)
  {
    if (!this._selected_element)
    {
      callback(null);
      return;
    }

    if (this._comp_style)
    {
      callback(this._comp_style);
      return;
    }

    var rt_id = this._selected_element.rt_id;
    var obj_id = this._selected_element.obj_id;

    if (this._stylesheets.has_stylesheets_runtime(rt_id))
    {
      var tag = this._tag_manager.set_callback(this, this._handle_get_metrics_data, [rt_id, obj_id, callback]);
      this._es_debugger.requestCssGetStyleDeclarations(tag, [rt_id, obj_id]);
    }
    else
    {
      this._stylesheets.get_stylesheets(this._selected_element.rt_id, this.get_layout_values.bind(this, callback));
    }
  };

  this._handle_get_metrics_data = function(status, message, rt_id, obj_id, callback, index_map)
  {
    var COMPUTED_STYLE_LIST = 0;
    var NODE_STYLE_LIST = 1;

    this._comp_style = message[COMPUTED_STYLE_LIST];
    if (!this._css_index_map)
    {
      if (!index_map)
      {
        window.stylesheets.get_css_index_map(this._handle_get_metrics_data.bind(this, status, message, rt_id, obj_id, callback));
        return;
      }
      else
      {
        this._css_index_map = index_map;
      }
    }

    if (callback)
      callback(this._comp_style);
  };

  this.get_offset_values = function(cb)
  {
    if (!this._selected_element)
    {
      cb(null);
    }
    else if (this._offset_values)
    {
      cb(window.helpers.copy_object(this._offset_values));
    }
    else
    {
      var rt_id = this._selected_element.rt_id;
      var obj_id = this._selected_element.obj_id;
      var tag = this._tag_manager.set_callback(null, this._handle_get_offset_data_bound, [rt_id, obj_id, cb]);
      this._es_debugger.requestEval(tag, [rt_id, 0, 0, OFFSETS_SCRIPT, [['ele', obj_id]]]);
    }
  };

  this._handle_get_offset_data = function(status, message, rt_id, obj_id, cb)
  {
    var STATUS = 0;
    var VALUE = 2;
    if (message[STATUS] == 'completed')
    {
      this._offset_values = this._parse_offset_values(message[VALUE]);
      if (cb)
        cb(window.helpers.copy_object(this._offset_values));
    }
    else
    {
      opera.postError(ui_strings.S_DRAGONFLY_INFO_MESSAGE +
        '_handle_get_offset_data failed')
    }
  };

  this._handle_get_offset_data_bound = this._handle_get_offset_data.bind(this);

  this._parse_offset_values = function(offset_values)
  {
    var data = offset_values.slice(0, -1).split(';'); // Remove the last ';' before splitting
    data[0] = data[0].split(',').map(function(item){
      return item.split('|');
    });
    return data;
  };

  this.get_metrics_template = function(comp_style)
  {
    var index_map = this._css_index_map;
    var is_positioned = comp_style[index_map.indexOf("position")] != "static";
    var is_border_box = comp_style[index_map.indexOf("box-sizing")] == "border-box";
    var width = this._get_dimension("width", comp_style, is_border_box);
    var height = this._get_dimension("height", comp_style, is_border_box);
    return (
      ['div',
        ['ul',
          ['li',
            ['ul',
              ['li',
                ['p',
                  '\u00A0',
                  ['span',
                    is_positioned
                    ? 'position'
                    : '\u00A0'
                  ]
                ]
              ],
              ['li',
                is_positioned
                ? this._convert_to_unitless(comp_style[index_map.indexOf("top")], true)
                : '\u00A0'
              ],
              ['li']
            ],
            ['ul',
              ['li',
                is_positioned
                ? this._convert_to_unitless(comp_style[index_map.indexOf("left")], true)
                : '\u00A0'
              ],
              ['li',
                ['ul',
                  ['li',
                    ['p',
                      '\u00a0',
                      ['span',
                        'margin'
                      ]
                    ]
                  ],
                  ['li',
                    this._convert_to_unitless(comp_style[index_map.indexOf("margin-top")])
                  ],
                  ['li']
                ],
                ['ul',
                  ['li',
                    this._convert_to_unitless(comp_style[index_map.indexOf("margin-left")])
                  ],
                  ['li',
                    ['ul',
                      ['li',
                        ['p',
                          '\u00a0',
                          ['span',
                            'border'
                          ]
                        ]
                      ],
                      ['li',
                        this._convert_to_unitless(comp_style[index_map.indexOf("border-top-width")])
                      ],
                      ['li']
                    ],
                    ['ul',
                      ['li',
                        this._convert_to_unitless(comp_style[index_map.indexOf("border-left-width")])
                      ],
                      ['li',
                        ['ul',
                          ['li',
                            ['p',
                              '\u00a0',
                              ['span',
                                'padding'
                              ]
                            ]
                          ],
                          ['li',
                            this._convert_to_unitless(comp_style[index_map.indexOf("padding-top")])
                          ],
                          ['li']
                        ],
                        ['ul',
                          ['li',
                            this._convert_to_unitless(comp_style[index_map.indexOf("padding-left")])
                          ],
                          ['li',
                            ['ul',
                              ['li',
                                '\u00a0'
                              ]
                            ],
                            ['ul',
                              ['li',
                                this._convert_to_unitless(width) +
                                ' × ' +
                                this._convert_to_unitless(height)
                              ]
                            ],
                            ['ul',
                              ['li',
                                '\u00a0'
                              ]
                            ],
                           'class', 'dimension'
                          ],
                          ['li',
                            this._convert_to_unitless(comp_style[index_map.indexOf("padding-right")])
                          ]
                        ],
                        ['ul',
                          ['li'],
                          ['li',
                            this._convert_to_unitless(comp_style[index_map.indexOf("padding-bottom")])
                          ],
                          ['li']
                        ],
                      'class', 'padding'
                      ],
                      ['li',
                        this._convert_to_unitless(comp_style[index_map.indexOf("border-right-width")])
                      ]
                    ],
                    ['ul',
                      ['li'],
                      ['li',
                        this._convert_to_unitless(comp_style[index_map.indexOf("border-bottom-width")])
                      ],
                      ['li']
                    ],
                   'class', 'border'
                  ],
                  ['li',
                    this._convert_to_unitless(comp_style[index_map.indexOf("margin-right")])
                  ]
                ],
                ['ul',
                  ['li'],
                  ['li',
                    this._convert_to_unitless(comp_style[index_map.indexOf("margin-bottom")])
                  ],
                  ['li']
                ],
               'class', 'margin'
              ],
              ['li',
                is_positioned
                ? this._convert_to_unitless(comp_style[index_map.indexOf("right")], true)
                : '\u00A0'
              ]
            ],
            ['ul',
              ['li'],
              ['li',
                is_positioned
                ? this._convert_to_unitless(comp_style[index_map.indexOf("bottom")], true)
                : '\u00A0'
              ],
              ['li']
            ],
           'class', is_positioned ? 'position' : ''
          ],
         'class', comp_style[index_map.indexOf("box-sizing")]
        ],
        ['table',
          ['tr',
            ['th',
              'position:'
            ],
            ['td',
              comp_style[index_map.indexOf("position")] || "–"
            ],
           'data-spec', 'css#position'
          ],
          ['tr',
            ['th',
              'z-index:'
            ],
            ['td',
              comp_style[index_map.indexOf("z-index")] || "–"
            ],
           'data-spec', 'css#z-index'
          ],
          ['tr',
            ['th',
              'box-sizing:'
            ],
            ['td',
              comp_style[index_map.indexOf("box-sizing")] || "–"
            ],
           'data-spec', 'css#box-sizing'
          ],
         'id', 'layout-info'
        ]
      ]
    );
  };

  this._get_dimension = function(direction, comp_style, is_border_box)
  {
    var index_map = this._css_index_map;
    var dim = parseInt(comp_style[index_map.indexOf(direction)]);
    var props = {
      "width": [
        "border-left",
        "border-right",
        "padding-left",
        "padding-right"
      ],
      "height": [
        "border-top",
        "border-bottom",
        "padding-top",
        "padding-bottom"
      ]
    };

    if (is_border_box)
    {
      dim += props[direction].reduce(function(prev, curr) {
        return prev - parseInt(comp_style[index_map.indexOf(curr)]);
      }, 0);
    }

    return dim;
  };

  this._convert_to_unitless = function(value, no_replace)
  {
    switch (value)
    {
    case "auto":
    case "":
      return "–";
    case "0px":
      return no_replace ? "0" : "–";
    default:
      return String(parseInt(value))
    }
  };

  window.messages.addListener('element-selected', this._on_element_selected.bind(this));
};

cls.ElementLayout.OFFSETS = [
  '',
  'offsetTop',
  'offsetLeft',
  'offsetWidth',
  'offsetHeight',
  'scrollTop',
  'scrollLeft',
  'scrollWidth',
  'scrollHeight',
  'clientTop',
  'clientLeft',
  'clientWidth',
  'clientHeight'
];

<|endoftext|>


<commit_before>/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2019
 */

/* eslint-disable quote-props */

export const INTERNAL_TO_EXTERNAL = 0;
export const EXTERNAL_TO_INTERNAL = 1;

class SyncTranslator {
  constructor(internalToExternal) {
    this.internalToExternal = internalToExternal;
    this.externalToInternal = {};
    // TODO: replace generators with explicit loops.
    // eslint-disable-next-line no-restricted-syntax
    for (const [key, value] of Object.entries(internalToExternal)) {
      this.externalToInternal[value] = key;
    }
  }

  translate(key, direction) {
    switch (direction) {
      case INTERNAL_TO_EXTERNAL:
      default:
        return this.internalToExternal[key];
      case EXTERNAL_TO_INTERNAL:
        return this.externalToInternal[key];
    }
  }
}

// Map of internal database object types to external record types.
export const RECORD_TYPES = new SyncTranslator({
  Item: 'item',
  ItemStoreJoin: 'item_store_join',
  ItemBatch: 'item_line',
  ItemDepartment: 'item_department',
  ItemCategory: 'item_category',
  LocalListItem: 'list_local_line',
  MasterList: 'list_master',
  MasterListItem: 'list_master_line',
  MasterListNameJoin: 'list_master_name_join',
  Name: 'name',
  NameStoreJoin: 'name_store_join',
  NumberSequence: 'number',
  NumberToReuse: 'number_reuse',
  Options: 'options',
  Period: 'period',
  PeriodSchedule: 'periodSchedule',
  Requisition: 'requisition',
  RequisitionItem: 'requisition_line',
  Stocktake: 'Stock_take',
  StocktakeBatch: 'Stock_take_lines',
  Store: 'store',
  Transaction: 'transact',
  TransactionCategory: 'transaction_category',
  TransactionBatch: 'trans_line',
  User: 'user',
  Unit: 'unit',
});

export const REQUISITION_TYPES = new SyncTranslator({
  imprest: 'im',
  forecast: 'sh',
  request: 'request',
  response: 'response',
});

// Map of internal database change types to external sync types.
export const SYNC_TYPES = new SyncTranslator({
  create: 'I', // For 'insert'
  update: 'U',
  delete: 'D',
  merge: 'M',
});

export const TRANSACTION_TYPES = new SyncTranslator({
  customer_invoice: 'ci',
  customer_credit: 'cc',
  supplier_invoice: 'si',
  supplier_credit: 'sc',
  inventory_adjustment: 'in',
  prescription: 'pi', // Following types provided for sync purposes, not actually used by mobile.
  build: 'bu',
  repack: 'sr',
  receipt: 'rc',
  payment: 'ps',
});

export const TRANSACTION_BATCH_TYPES = new SyncTranslator({
  customer_invoice: 'stock_out',
  customer_credit: 'stock_in',
  supplier_invoice: 'stock_in',
  supplier_credit: 'stock_out',
});

export const NAME_TYPES = new SyncTranslator({
  inventory_adjustment: 'invad',
  facility: 'facility',
  patient: 'patient',
  build: 'build',
  store: 'store',
  repack: 'repack',
});

/**
 * Translates requisition statuses, which will be changed by the supplying store
 * once finalised in the mobile store. Despite the supplying store's requisition
 * going through 'sg', 'cn', and 'fn' statuses, it should remain finalised in the
 * mobile store.
 */
class RequisitionStatusTranslator extends SyncTranslator {
  translate(status, direction) {
    if (['cn', 'wf'].includes(status)) return 'finalised';
    return super.translate(status, direction);
  }
}
export const REQUISITION_STATUSES = new RequisitionStatusTranslator({
  new: 'wp', // 'wp', 'wf', 'cn' should never be returned in api/v3.
  suggested: 'sg',
  finalised: 'fn',
});

/**
 * Translates statuses of transactions, stocktakes, etc., which include 'wp' and 'wf'
 * on legacy systems.
 */
class StatusTranslator extends SyncTranslator {
  translate(status, direction) {
    switch (status) {
      case 'wp':
        return 'new';
      case 'wf':
        return 'finalised';
      default:
        return super.translate(status, direction);
    }
  }
}
// Map of internal statuses to external statuses (of transactions, stocktakes, etc.).
export const STATUSES = new StatusTranslator({
  confirmed: 'cn',
  finalised: 'fn',
  suggested: 'sg',
  new: 'nw',
});

/**
 * Translates number sequence keys from internal to external formats, and vice versa.
 * If translating external to internal, will return null if it is a sequence key
 * not used by mobile, or if it relates to a different store.
 */
class SequenceKeyTranslator extends SyncTranslator {
  translate(sequenceKey, direction, thisStoreId) {
    let key = sequenceKey;
    if (direction === EXTERNAL_TO_INTERNAL) {
      if (key.length < thisStoreId.length) return null; // Not a key used here.
      // Relevamt mSupply sequence keys end with the store id they relate to.
      const storeId = key.substring(key.length - thisStoreId.length);
      // If the sequence doesn't relate to this store, ignore.
      if (storeId !== thisStoreId) return null;
      key = key.substring(0, key.length - thisStoreId.length);
    }
    let translatedKey = super.translate(key, direction);
    if (direction === INTERNAL_TO_EXTERNAL) translatedKey += thisStoreId;
    return translatedKey;
  }
}
export const SEQUENCE_KEYS = new SequenceKeyTranslator({
  customer_invoice_serial_number: 'customer_invoice_number_for_store_',
  inventory_adjustment_serial_number: 'inventory_adjustment_serial_number_for_store_',
  requisition_serial_number: 'requisition_serial_number_for_store_',
  requisition_requester_reference: 'requisition_requester_reference_for_store_',
  stocktake_serial_number: 'stock_take_number_for_store_',
  supplier_invoice_serial_number: 'supplier_invoice_number_for_store_',
});
<commit_msg>Add Message to SyncTranslations<commit_after>/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2019
 */

/* eslint-disable quote-props */

export const INTERNAL_TO_EXTERNAL = 0;
export const EXTERNAL_TO_INTERNAL = 1;

class SyncTranslator {
  constructor(internalToExternal) {
    this.internalToExternal = internalToExternal;
    this.externalToInternal = {};
    // TODO: replace generators with explicit loops.
    // eslint-disable-next-line no-restricted-syntax
    for (const [key, value] of Object.entries(internalToExternal)) {
      this.externalToInternal[value] = key;
    }
  }

  translate(key, direction) {
    switch (direction) {
      case INTERNAL_TO_EXTERNAL:
      default:
        return this.internalToExternal[key];
      case EXTERNAL_TO_INTERNAL:
        return this.externalToInternal[key];
    }
  }
}

// Map of internal database object types to external record types.
export const RECORD_TYPES = new SyncTranslator({
  Item: 'item',
  ItemStoreJoin: 'item_store_join',
  ItemBatch: 'item_line',
  ItemDepartment: 'item_department',
  ItemCategory: 'item_category',
  LocalListItem: 'list_local_line',
  MasterList: 'list_master',
  MasterListItem: 'list_master_line',
  MasterListNameJoin: 'list_master_name_join',
  Message: 'message',
  Name: 'name',
  NameStoreJoin: 'name_store_join',
  NumberSequence: 'number',
  NumberToReuse: 'number_reuse',
  Options: 'options',
  Period: 'period',
  PeriodSchedule: 'periodSchedule',
  Requisition: 'requisition',
  RequisitionItem: 'requisition_line',
  Stocktake: 'Stock_take',
  StocktakeBatch: 'Stock_take_lines',
  Store: 'store',
  Transaction: 'transact',
  TransactionCategory: 'transaction_category',
  TransactionBatch: 'trans_line',
  User: 'user',
  Unit: 'unit',
});

export const REQUISITION_TYPES = new SyncTranslator({
  imprest: 'im',
  forecast: 'sh',
  request: 'request',
  response: 'response',
});

// Map of internal database change types to external sync types.
export const SYNC_TYPES = new SyncTranslator({
  create: 'I', // For 'insert'
  update: 'U',
  delete: 'D',
  merge: 'M',
});

export const TRANSACTION_TYPES = new SyncTranslator({
  customer_invoice: 'ci',
  customer_credit: 'cc',
  supplier_invoice: 'si',
  supplier_credit: 'sc',
  inventory_adjustment: 'in',
  prescription: 'pi', // Following types provided for sync purposes, not actually used by mobile.
  build: 'bu',
  repack: 'sr',
  receipt: 'rc',
  payment: 'ps',
});

export const TRANSACTION_BATCH_TYPES = new SyncTranslator({
  customer_invoice: 'stock_out',
  customer_credit: 'stock_in',
  supplier_invoice: 'stock_in',
  supplier_credit: 'stock_out',
});

export const NAME_TYPES = new SyncTranslator({
  inventory_adjustment: 'invad',
  facility: 'facility',
  patient: 'patient',
  build: 'build',
  store: 'store',
  repack: 'repack',
});

/**
 * Translates requisition statuses, which will be changed by the supplying store
 * once finalised in the mobile store. Despite the supplying store's requisition
 * going through 'sg', 'cn', and 'fn' statuses, it should remain finalised in the
 * mobile store.
 */
class RequisitionStatusTranslator extends SyncTranslator {
  translate(status, direction) {
    if (['cn', 'wf'].includes(status)) return 'finalised';
    return super.translate(status, direction);
  }
}
export const REQUISITION_STATUSES = new RequisitionStatusTranslator({
  new: 'wp', // 'wp', 'wf', 'cn' should never be returned in api/v3.
  suggested: 'sg',
  finalised: 'fn',
});

/**
 * Translates statuses of transactions, stocktakes, etc., which include 'wp' and 'wf'
 * on legacy systems.
 */
class StatusTranslator extends SyncTranslator {
  translate(status, direction) {
    switch (status) {
      case 'wp':
        return 'new';
      case 'wf':
        return 'finalised';
      default:
        return super.translate(status, direction);
    }
  }
}
// Map of internal statuses to external statuses (of transactions, stocktakes, etc.).
export const STATUSES = new StatusTranslator({
  confirmed: 'cn',
  finalised: 'fn',
  suggested: 'sg',
  new: 'nw',
});

/**
 * Translates number sequence keys from internal to external formats, and vice versa.
 * If translating external to internal, will return null if it is a sequence key
 * not used by mobile, or if it relates to a different store.
 */
class SequenceKeyTranslator extends SyncTranslator {
  translate(sequenceKey, direction, thisStoreId) {
    let key = sequenceKey;
    if (direction === EXTERNAL_TO_INTERNAL) {
      if (key.length < thisStoreId.length) return null; // Not a key used here.
      // Relevamt mSupply sequence keys end with the store id they relate to.
      const storeId = key.substring(key.length - thisStoreId.length);
      // If the sequence doesn't relate to this store, ignore.
      if (storeId !== thisStoreId) return null;
      key = key.substring(0, key.length - thisStoreId.length);
    }
    let translatedKey = super.translate(key, direction);
    if (direction === INTERNAL_TO_EXTERNAL) translatedKey += thisStoreId;
    return translatedKey;
  }
}
export const SEQUENCE_KEYS = new SequenceKeyTranslator({
  customer_invoice_serial_number: 'customer_invoice_number_for_store_',
  inventory_adjustment_serial_number: 'inventory_adjustment_serial_number_for_store_',
  requisition_serial_number: 'requisition_serial_number_for_store_',
  requisition_requester_reference: 'requisition_requester_reference_for_store_',
  stocktake_serial_number: 'stock_take_number_for_store_',
  supplier_invoice_serial_number: 'supplier_invoice_number_for_store_',
});
<|endoftext|>