<commit_before>/*
 *
 * (c) Copyright Ascensio System SIA 2010-2019
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha
 * street, Riga, Latvia, EU, LV-1050.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

/**
 *  Links.js
 *
 *  Created by Julia Radzhabova on 22.12.2017
 *  Copyright (c) 2018 Ascensio System SIA. All rights reserved.
 *
 */

define([
    'core',
    'documenteditor/main/app/view/Links',
    'documenteditor/main/app/view/NoteSettingsDialog',
    'documenteditor/main/app/view/HyperlinkSettingsDialog',
    'documenteditor/main/app/view/TableOfContentsSettings',
    'documenteditor/main/app/view/BookmarksDialog',
    'documenteditor/main/app/view/CaptionDialog'
], function () {
    'use strict';

    DE.Controllers.Links = Backbone.Controller.extend(_.extend({
        models : [],
        collections : [
        ],
        views : [
            'Links'
        ],
        sdkViewName : '#id_main',

        initialize: function () {

            this.addListeners({
                'Links': {
                    'links:contents': this.onTableContents,
                    'links:update': this.onTableContentsUpdate,
                    'links:notes': this.onNotesClick,
                    'links:hyperlink': this.onHyperlinkClick,
                    'links:bookmarks': this.onBookmarksClick,
                    'links:caption': this.onCaptionClick
                },
                'DocumentHolder': {
                    'links:contents': this.onTableContents,
                    'links:update': this.onTableContentsUpdate
                }
            });
        },
        onLaunch: function () {
            this._state = {
                prcontrolsdisable:undefined,
                in_object: false
            };
            Common.Gateway.on('setactionlink', function (url) {
                console.log('url with actions: ' + url);
            }.bind(this));
        },

        setApi: function (api) {
            if (api) {
                this.api = api;
                this.api.asc_registerCallback('asc_onFocusObject', this.onApiFocusObject.bind(this));
                this.api.asc_registerCallback('asc_onCanAddHyperlink',      _.bind(this.onApiCanAddHyperlink, this));
                this.api.asc_registerCallback('asc_onCoAuthoringDisconnect',_.bind(this.onCoAuthoringDisconnect, this));
                Common.NotificationCenter.on('api:disconnect', _.bind(this.onCoAuthoringDisconnect, this));
                this.api.asc_registerCallback('asc_onShowContentControlsActions',_.bind(this.onShowContentControlsActions, this));
                this.api.asc_registerCallback('asc_onHideContentControlsActions',_.bind(this.onHideContentControlsActions, this));
            }
            return this;
        },

        setConfig: function(config) {
            this.toolbar = config.toolbar;
            this.view = this.createView('Links', {
                toolbar: this.toolbar.toolbar
            });
        },

        SetDisabled: function(state) {
            this.view && this.view.SetDisabled(state);
        },

        getView: function(name) {
            return !name && this.view ?
                this.view : Backbone.Controller.prototype.getView.call(this, name);
        },

        onCoAuthoringDisconnect: function() {
            this.SetDisabled(true);
        },

        onApiFocusObject: function(selectedObjects) {
            if (!this.toolbar.editMode) return;

            var pr, i = -1, type,
                paragraph_locked = false,
                header_locked = false,
                in_header = false,
                in_equation = false,
                in_image = false,
                in_table = false,
                frame_pr = null;

            while (++i < selectedObjects.length) {
                type = selectedObjects[i].get_ObjectType();
                pr   = selectedObjects[i].get_ObjectValue();

                if (type === Asc.c_oAscTypeSelectElement.Paragraph) {
                    paragraph_locked = pr.get_Locked();
                    frame_pr = pr;
                } else if (type === Asc.c_oAscTypeSelectElement.Header) {
                    header_locked = pr.get_Locked();
                    in_header = true;
                } else if (type === Asc.c_oAscTypeSelectElement.Image) {
                    in_image = true;
                } else if (type === Asc.c_oAscTypeSelectElement.Math) {
                    in_equation = true;
                } else if (type === Asc.c_oAscTypeSelectElement.Table) {
                    in_table = true;
                }
            }
            this._state.prcontrolsdisable = paragraph_locked || header_locked;
            this._state.in_object = in_image || in_table || in_equation;

            var control_props = this.api.asc_IsContentControl() ? this.api.asc_GetContentControlProperties() : null,
                control_plain = (control_props) ? (control_props.get_ContentControlType()==Asc.c_oAscSdtLevelType.Inline) : false;
            var rich_del_lock = (frame_pr) ? !frame_pr.can_DeleteBlockContentControl() : false,
                rich_edit_lock = (frame_pr) ? !frame_pr.can_EditBlockContentControl() : false,
                plain_del_lock = (frame_pr) ? !frame_pr.can_DeleteInlineContentControl() : false,
                plain_edit_lock = (frame_pr) ? !frame_pr.can_EditInlineContentControl() : false;

            var need_disable = paragraph_locked || in_equation || in_image || in_header || control_plain || rich_edit_lock || plain_edit_lock;
            this.view.btnsNotes.setDisabled(need_disable);

            need_disable = paragraph_locked || header_locked || in_header || control_plain;
            this.view.btnBookmarks.setDisabled(need_disable);

            need_disable = in_header || rich_edit_lock || plain_edit_lock || rich_del_lock || plain_del_lock;
            this.view.btnsContents.setDisabled(need_disable);

            need_disable = in_header;
            this.view.btnCaption.setDisabled(need_disable);
        },

        onApiCanAddHyperlink: function(value) {
            this.toolbar.editMode && this.view.btnsHyperlink.setDisabled(!value || this._state.prcontrolsdisable);
        },

        onHyperlinkClick: function(btn) {
            var me = this,
                win, props, text;

            if (me.api){

                var handlerDlg = function(dlg, result) {
                    if (result == 'ok') {
                        props = dlg.getSettings();
                        (text!==false)
                            ? me.api.add_Hyperlink(props)
                            : me.api.change_Hyperlink(props);
                    }

                    Common.NotificationCenter.trigger('edit:complete', me.toolbar);
                };

                text = me.api.can_AddHyperlink();

                if (text !== false) {
                    win = new DE.Views.HyperlinkSettingsDialog({
                        api: me.api,
                        handler: handlerDlg
                    });

                    props = new Asc.CHyperlinkProperty();
                    props.put_Text(text);

                    win.show();
                    win.setSettings(props);
                } else {
                    var selectedElements = me.api.getSelectedElements();
                    if (selectedElements && _.isArray(selectedElements)){
                        _.each(selectedElements, function(el, i) {
                            if (selectedElements[i].get_ObjectType() == Asc.c_oAscTypeSelectElement.Hyperlink)
                                props = selectedElements[i].get_ObjectValue();
                        });
                    }
                    if (props) {
                        win = new DE.Views.HyperlinkSettingsDialog({
                            api: me.api,
                            handler: handlerDlg
                        });
                        win.show();
                        win.setSettings(props);
                    }
                }
            }

            Common.component.Analytics.trackEvent('ToolBar', 'Add Hyperlink');
        },

        onTableContents: function(type, currentTOC){
            currentTOC = !!currentTOC;
            var props = this.api.asc_GetTableOfContentsPr(currentTOC);
            switch (type) {
                case 0:
                    if (!props) {
                        props = new Asc.CTableOfContentsPr();
                        props.put_OutlineRange(1, 9);
                    }
                    props.put_Hyperlink(true);
                    props.put_ShowPageNumbers(true);
                    props.put_RightAlignTab(true);
                    props.put_TabLeader( Asc.c_oAscTabLeader.Dot);
                    (currentTOC) ? this.api.asc_SetTableOfContentsPr(props) : this.api.asc_AddTableOfContents(null, props);
                    break;
                case 1:
                    if (!props) {
                        props = new Asc.CTableOfContentsPr();
                        props.put_OutlineRange(1, 9);
                    }
                    props.put_Hyperlink(true);
                    props.put_ShowPageNumbers(false);
                    props.put_TabLeader( Asc.c_oAscTabLeader.None);
                    props.put_StylesType(Asc.c_oAscTOCStylesType.Web);
                    (currentTOC) ? this.api.asc_SetTableOfContentsPr(props) : this.api.asc_AddTableOfContents(null, props);
                    break;
                case 'settings':
                    var me = this,
                        win = new DE.Views.TableOfContentsSettings({
                        api: this.api,
                        props: props,
                        handler: function(result, value) {
                            if (result == 'ok') {
                                (props) ? me.api.asc_SetTableOfContentsPr(value) : me.api.asc_AddTableOfContents(null, value);
                            }
                            Common.NotificationCenter.trigger('edit:complete', me.toolbar);
                        }
                    });
                    win.show();
                    break;
                case 'remove':
                    currentTOC = (currentTOC && props) ? props.get_InternalClass() : undefined;
                    this.api.asc_RemoveTableOfContents(currentTOC);
                    break;
            }
            Common.NotificationCenter.trigger('edit:complete', this.toolbar);
        },

        onTableContentsUpdate: function(type, currentTOC){
            var props = this.api.asc_GetTableOfContentsPr(currentTOC);
            if (props) {
                if (currentTOC && props)
                    currentTOC = props.get_InternalClass();
                this.api.asc_UpdateTableOfContents(type == 'pages', currentTOC);
            }
            Common.NotificationCenter.trigger('edit:complete', this.toolbar);
        },

        onNotesClick: function(type) {
            var me = this;
            switch (type) {
                case 'ins_footnote':
                    this.api.asc_AddFootnote();
                    break;
                case 'delele':
                    Common.UI.warning({
                        msg: this.view.confirmDeleteFootnotes,
                        buttons: ['yes', 'no'],
                        primary: 'yes',
                        callback: _.bind(function (btn) {
                            if (btn == 'yes') {
                                this.api.asc_RemoveAllFootnotes();
                            }
                            Common.NotificationCenter.trigger('edit:complete', this.toolbar);
                        }, this)
                    });
                    break;
                case 'settings':
                    (new DE.Views.NoteSettingsDialog({
                        api: me.api,
                        handler: function (result, settings) {
                            if (settings) {
                                me.api.asc_SetFootnoteProps(settings.props, settings.applyToAll);
                                if (result == 'insert')
                                    setTimeout(function() {
                                        me.api.asc_AddFootnote(settings.custom);
                                    }, 1);
                            }
                            Common.NotificationCenter.trigger('edit:complete', me.toolbar);
                        },
                        props: me.api.asc_GetFootnoteProps()
                    })).show();
                    break;
                case 'prev':
                    this.api.asc_GotoFootnote(false);
                    setTimeout(function() {
                        Common.NotificationCenter.trigger('edit:complete', me.toolbar);
                    }, 50);
                    break;
                case 'next':
                    this.api.asc_GotoFootnote(true);
                    setTimeout(function() {
                        Common.NotificationCenter.trigger('edit:complete', me.toolbar);
                    }, 50);
                    break;
            }
        },

        onBookmarksClick: function(btn) {
            var me = this;
            (new DE.Views.BookmarksDialog({
                api: me.api,
                appOptions: me.toolbar.appOptions,
                props: me.api.asc_GetBookmarksManager(),
                handler: function (result, settings) {
                    if (settings) {
                    }
                    Common.NotificationCenter.trigger('edit:complete', me.toolbar);
                }
            })).show();
        },

        onCaptionClick: function(btn) {
            var me = this;
            (new DE.Views.CaptionDialog({
                isObject: this._state.in_object,
                handler: function (result, settings) {
                    if (result == 'ok') {
                        me.api.asc_AddObjectCaption(settings);
                    }
                    Common.NotificationCenter.trigger('edit:complete', me.toolbar);
                }
            })).show();
        },

        onShowTOCActions: function(obj, x, y) {
            var action = obj.button,
                menu = (action==AscCommon.CCButtonType.Toc) ? this.view.contentsUpdateMenu : this.view.contentsMenu,
                documentHolderView  = this.getApplication().getController('DocumentHolder').documentHolder,
                menuContainer = documentHolderView.cmpEl.find(Common.Utils.String.format('#menu-container-{0}', menu.id)),
                me = this;

            if (!menu) return;
            this._fromShowContentControls = true;
            Common.UI.Menu.Manager.hideAll();

            if (!menu.rendered) {
                // Prepare menu container
                if (menuContainer.length < 1) {
                    menuContainer = $(Common.Utils.String.format('

', menu.id));
                    documentHolderView.cmpEl.append(menuContainer);
                }

                menu.render(menuContainer);
                menu.cmpEl.attr({tabindex: "-1"});
                menu.on('hide:after', function(){
                    if (!me._fromShowContentControls)
                        me.api.asc_UncheckContentControlButtons();
                });
            }

            menuContainer.css({left: x, top : y});
            menuContainer.attr('data-value', 'prevent-canvas-click');
            documentHolderView._preventClick = true;
            menu.show();

            menu.alignPosition();
            _.delay(function() {
                menu.cmpEl.focus();
            }, 10);
            this._fromShowContentControls = false;
        },

        onHideContentControlsActions: function() {
            this.view.contentsMenu && this.view.contentsMenu.hide();
            this.view.contentsUpdateMenu && this.view.contentsUpdateMenu.hide();
        },

        onShowContentControlsActions: function(obj, x, y) {
            (obj.type == Asc.c_oAscContentControlSpecificType.TOC) && this.onShowTOCActions(obj, x, y);
        }

    }, DE.Controllers.Links || {}));
});<commit_msg>[DE] Fix Bug 46117<commit_after>/*
 *
 * (c) Copyright Ascensio System SIA 2010-2019
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha
 * street, Riga, Latvia, EU, LV-1050.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

/**
 *  Links.js
 *
 *  Created by Julia Radzhabova on 22.12.2017
 *  Copyright (c) 2018 Ascensio System SIA. All rights reserved.
 *
 */

define([
    'core',
    'documenteditor/main/app/view/Links',
    'documenteditor/main/app/view/NoteSettingsDialog',
    'documenteditor/main/app/view/HyperlinkSettingsDialog',
    'documenteditor/main/app/view/TableOfContentsSettings',
    'documenteditor/main/app/view/BookmarksDialog',
    'documenteditor/main/app/view/CaptionDialog'
], function () {
    'use strict';

    DE.Controllers.Links = Backbone.Controller.extend(_.extend({
        models : [],
        collections : [
        ],
        views : [
            'Links'
        ],
        sdkViewName : '#id_main',

        initialize: function () {

            this.addListeners({
                'Links': {
                    'links:contents': this.onTableContents,
                    'links:update': this.onTableContentsUpdate,
                    'links:notes': this.onNotesClick,
                    'links:hyperlink': this.onHyperlinkClick,
                    'links:bookmarks': this.onBookmarksClick,
                    'links:caption': this.onCaptionClick
                },
                'DocumentHolder': {
                    'links:contents': this.onTableContents,
                    'links:update': this.onTableContentsUpdate
                }
            });
        },
        onLaunch: function () {
            this._state = {
                prcontrolsdisable:undefined,
                in_object: false
            };
            Common.Gateway.on('setactionlink', function (url) {
                console.log('url with actions: ' + url);
            }.bind(this));
        },

        setApi: function (api) {
            if (api) {
                this.api = api;
                this.api.asc_registerCallback('asc_onFocusObject', this.onApiFocusObject.bind(this));
                this.api.asc_registerCallback('asc_onCanAddHyperlink',      _.bind(this.onApiCanAddHyperlink, this));
                this.api.asc_registerCallback('asc_onCoAuthoringDisconnect',_.bind(this.onCoAuthoringDisconnect, this));
                Common.NotificationCenter.on('api:disconnect', _.bind(this.onCoAuthoringDisconnect, this));
                this.api.asc_registerCallback('asc_onShowContentControlsActions',_.bind(this.onShowContentControlsActions, this));
                this.api.asc_registerCallback('asc_onHideContentControlsActions',_.bind(this.onHideContentControlsActions, this));
            }
            return this;
        },

        setConfig: function(config) {
            this.toolbar = config.toolbar;
            this.view = this.createView('Links', {
                toolbar: this.toolbar.toolbar
            });
        },

        SetDisabled: function(state) {
            this.view && this.view.SetDisabled(state);
        },

        getView: function(name) {
            return !name && this.view ?
                this.view : Backbone.Controller.prototype.getView.call(this, name);
        },

        onCoAuthoringDisconnect: function() {
            this.SetDisabled(true);
        },

        onApiFocusObject: function(selectedObjects) {
            if (!this.toolbar.editMode) return;

            var pr, i = -1, type,
                paragraph_locked = false,
                header_locked = false,
                in_header = false,
                in_equation = false,
                in_image = false,
                in_table = false,
                frame_pr = null;

            while (++i < selectedObjects.length) {
                type = selectedObjects[i].get_ObjectType();
                pr   = selectedObjects[i].get_ObjectValue();

                if (type === Asc.c_oAscTypeSelectElement.Paragraph) {
                    paragraph_locked = pr.get_Locked();
                    frame_pr = pr;
                } else if (type === Asc.c_oAscTypeSelectElement.Header) {
                    header_locked = pr.get_Locked();
                    in_header = true;
                } else if (type === Asc.c_oAscTypeSelectElement.Image) {
                    in_image = true;
                } else if (type === Asc.c_oAscTypeSelectElement.Math) {
                    in_equation = true;
                } else if (type === Asc.c_oAscTypeSelectElement.Table) {
                    in_table = true;
                }
            }
            this._state.prcontrolsdisable = paragraph_locked || header_locked;
            this._state.in_object = in_image || in_table || in_equation;

            var control_props = this.api.asc_IsContentControl() ? this.api.asc_GetContentControlProperties() : null,
                control_plain = (control_props) ? (control_props.get_ContentControlType()==Asc.c_oAscSdtLevelType.Inline) : false;
            var rich_del_lock = (frame_pr) ? !frame_pr.can_DeleteBlockContentControl() : false,
                rich_edit_lock = (frame_pr) ? !frame_pr.can_EditBlockContentControl() : false,
                plain_del_lock = (frame_pr) ? !frame_pr.can_DeleteInlineContentControl() : false,
                plain_edit_lock = (frame_pr) ? !frame_pr.can_EditInlineContentControl() : false;

            var need_disable = paragraph_locked || in_equation || in_image || in_header || control_plain || rich_edit_lock || plain_edit_lock;
            this.view.btnsNotes.setDisabled(need_disable);

            need_disable = paragraph_locked || header_locked || in_header || control_plain;
            this.view.btnBookmarks.setDisabled(need_disable);

            need_disable = in_header || rich_edit_lock || plain_edit_lock || rich_del_lock || plain_del_lock;
            this.view.btnsContents.setDisabled(need_disable);

            need_disable = in_header;
            this.view.btnCaption.setDisabled(need_disable);
        },

        onApiCanAddHyperlink: function(value) {
            this.toolbar.editMode && this.view.btnsHyperlink.setDisabled(!value || this._state.prcontrolsdisable);
        },

        onHyperlinkClick: function(btn) {
            var me = this,
                win, props, text;

            if (me.api){

                var handlerDlg = function(dlg, result) {
                    if (result == 'ok') {
                        props = dlg.getSettings();
                        (text!==false)
                            ? me.api.add_Hyperlink(props)
                            : me.api.change_Hyperlink(props);
                    }

                    Common.NotificationCenter.trigger('edit:complete', me.toolbar);
                };

                text = me.api.can_AddHyperlink();

                if (text !== false) {
                    win = new DE.Views.HyperlinkSettingsDialog({
                        api: me.api,
                        handler: handlerDlg
                    });

                    props = new Asc.CHyperlinkProperty();
                    props.put_Text(text);

                    win.show();
                    win.setSettings(props);
                } else {
                    var selectedElements = me.api.getSelectedElements();
                    if (selectedElements && _.isArray(selectedElements)){
                        _.each(selectedElements, function(el, i) {
                            if (selectedElements[i].get_ObjectType() == Asc.c_oAscTypeSelectElement.Hyperlink)
                                props = selectedElements[i].get_ObjectValue();
                        });
                    }
                    if (props) {
                        win = new DE.Views.HyperlinkSettingsDialog({
                            api: me.api,
                            handler: handlerDlg
                        });
                        win.show();
                        win.setSettings(props);
                    }
                }
            }

            Common.component.Analytics.trackEvent('ToolBar', 'Add Hyperlink');
        },

        onTableContents: function(type, currentTOC){
            currentTOC = !!currentTOC;
            var props = this.api.asc_GetTableOfContentsPr(currentTOC);
            switch (type) {
                case 0:
                    if (!props) {
                        props = new Asc.CTableOfContentsPr();
                        props.put_OutlineRange(1, 9);
                    }
                    props.put_Hyperlink(true);
                    props.put_ShowPageNumbers(true);
                    props.put_RightAlignTab(true);
                    props.put_TabLeader( Asc.c_oAscTabLeader.Dot);
                    (currentTOC) ? this.api.asc_SetTableOfContentsPr(props) : this.api.asc_AddTableOfContents(null, props);
                    break;
                case 1:
                    if (!props) {
                        props = new Asc.CTableOfContentsPr();
                        props.put_OutlineRange(1, 9);
                    }
                    props.put_Hyperlink(true);
                    props.put_ShowPageNumbers(false);
                    props.put_TabLeader( Asc.c_oAscTabLeader.None);
                    props.put_StylesType(Asc.c_oAscTOCStylesType.Web);
                    (currentTOC) ? this.api.asc_SetTableOfContentsPr(props) : this.api.asc_AddTableOfContents(null, props);
                    break;
                case 'settings':
                    var me = this,
                        win = new DE.Views.TableOfContentsSettings({
                        api: this.api,
                        props: props,
                        handler: function(result, value) {
                            if (result == 'ok') {
                                (props) ? me.api.asc_SetTableOfContentsPr(value) : me.api.asc_AddTableOfContents(null, value);
                            }
                            Common.NotificationCenter.trigger('edit:complete', me.toolbar);
                        }
                    });
                    win.show();
                    break;
                case 'remove':
                    currentTOC = (currentTOC && props) ? props.get_InternalClass() : undefined;
                    this.api.asc_RemoveTableOfContents(currentTOC);
                    break;
            }
            Common.NotificationCenter.trigger('edit:complete', this.toolbar);
        },

        onTableContentsUpdate: function(type, currentTOC){
            var props = this.api.asc_GetTableOfContentsPr(currentTOC);
            if (props) {
                if (currentTOC && props)
                    currentTOC = props.get_InternalClass();
                this.api.asc_UpdateTableOfContents(type == 'pages', currentTOC);
            }
            Common.NotificationCenter.trigger('edit:complete', this.toolbar);
        },

        onNotesClick: function(type) {
            var me = this;
            switch (type) {
                case 'ins_footnote':
                    this.api.asc_AddFootnote();
                    break;
                case 'delele':
                    Common.UI.warning({
                        msg: this.view.confirmDeleteFootnotes,
                        buttons: ['yes', 'no'],
                        primary: 'yes',
                        callback: _.bind(function (btn) {
                            if (btn == 'yes') {
                                this.api.asc_RemoveAllFootnotes(true, false);
                            }
                            Common.NotificationCenter.trigger('edit:complete', this.toolbar);
                        }, this)
                    });
                    break;
                case 'settings':
                    (new DE.Views.NoteSettingsDialog({
                        api: me.api,
                        handler: function (result, settings) {
                            if (settings) {
                                me.api.asc_SetFootnoteProps(settings.props, settings.applyToAll);
                                if (result == 'insert')
                                    setTimeout(function() {
                                        me.api.asc_AddFootnote(settings.custom);
                                    }, 1);
                            }
                            Common.NotificationCenter.trigger('edit:complete', me.toolbar);
                        },
                        props: me.api.asc_GetFootnoteProps()
                    })).show();
                    break;
                case 'prev':
                    this.api.asc_GotoFootnote(false);
                    setTimeout(function() {
                        Common.NotificationCenter.trigger('edit:complete', me.toolbar);
                    }, 50);
                    break;
                case 'next':
                    this.api.asc_GotoFootnote(true);
                    setTimeout(function() {
                        Common.NotificationCenter.trigger('edit:complete', me.toolbar);
                    }, 50);
                    break;
            }
        },

        onBookmarksClick: function(btn) {
            var me = this;
            (new DE.Views.BookmarksDialog({
                api: me.api,
                appOptions: me.toolbar.appOptions,
                props: me.api.asc_GetBookmarksManager(),
                handler: function (result, settings) {
                    if (settings) {
                    }
                    Common.NotificationCenter.trigger('edit:complete', me.toolbar);
                }
            })).show();
        },

        onCaptionClick: function(btn) {
            var me = this;
            (new DE.Views.CaptionDialog({
                isObject: this._state.in_object,
                handler: function (result, settings) {
                    if (result == 'ok') {
                        me.api.asc_AddObjectCaption(settings);
                    }
                    Common.NotificationCenter.trigger('edit:complete', me.toolbar);
                }
            })).show();
        },

        onShowTOCActions: function(obj, x, y) {
            var action = obj.button,
                menu = (action==AscCommon.CCButtonType.Toc) ? this.view.contentsUpdateMenu : this.view.contentsMenu,
                documentHolderView  = this.getApplication().getController('DocumentHolder').documentHolder,
                menuContainer = documentHolderView.cmpEl.find(Common.Utils.String.format('#menu-container-{0}', menu.id)),
                me = this;

            if (!menu) return;
            this._fromShowContentControls = true;
            Common.UI.Menu.Manager.hideAll();

            if (!menu.rendered) {
                // Prepare menu container
                if (menuContainer.length < 1) {
                    menuContainer = $(Common.Utils.String.format('

', menu.id));
                    documentHolderView.cmpEl.append(menuContainer);
                }

                menu.render(menuContainer);
                menu.cmpEl.attr({tabindex: "-1"});
                menu.on('hide:after', function(){
                    if (!me._fromShowContentControls)
                        me.api.asc_UncheckContentControlButtons();
                });
            }

            menuContainer.css({left: x, top : y});
            menuContainer.attr('data-value', 'prevent-canvas-click');
            documentHolderView._preventClick = true;
            menu.show();

            menu.alignPosition();
            _.delay(function() {
                menu.cmpEl.focus();
            }, 10);
            this._fromShowContentControls = false;
        },

        onHideContentControlsActions: function() {
            this.view.contentsMenu && this.view.contentsMenu.hide();
            this.view.contentsUpdateMenu && this.view.contentsUpdateMenu.hide();
        },

        onShowContentControlsActions: function(obj, x, y) {
            (obj.type == Asc.c_oAscContentControlSpecificType.TOC) && this.onShowTOCActions(obj, x, y);
        }

    }, DE.Controllers.Links || {}));
});<|endoftext|>


<commit_before>(function(DOM, DateUtils) {
    "use strict";

    var __ = DOM.__;
    var pad = (num, maxlen) => ("00" + num).slice(-maxlen);

    DOM.extend("time[is=local-time]", {
        constructor() {
            this.on("change", this._changeValue.bind(this));

            this._changeValue();
        },
        _changeValue() {
            var datetimeText = this.get("datetime");

            if (!datetimeText) return;

            var value = new Date(datetimeText),
                formattedValue = "";

            if (!value.getTime()) {
                formattedValue = value.toString();
            } else {
                var formatString = this.get("data-format");
                // use "E, dd MMM yyyy H:mm:ss" as default value
                if (!formatString) formatString = "E, dd MMM yyyy H:mm:ss";

                formattedValue = formatString.replace(/\w+/g, (str) => {
                    switch (str) {
                        case "H": str = value.getHours(); break;
                        case "HH": str = pad(value.getHours(), 2); break;
                        case "h": str = value.getHours() % 12 || 12; break;
                        case "hh": str = pad(value.getHours() % 12 || 12, 2); break;
                        case "m": str = value.getMinutes(); break;
                        case "mm": str = pad(value.getMinutes(), 2); break;
                        case "s": str = value.getSeconds(); break;
                        case "ss": str = pad(value.getSeconds(), 2); break;
                        case "E": str = __(DateUtils.DAYS[value.getUTCDay()].slice(0, 2)); break;
                        case "EE": str = __(DateUtils.DAYS[value.getUTCDay()]); break;
                        case "d": str = value.getDate(); break;
                        case "dd": str = pad(value.getDate(), 2); break;
                        case "D": str = DateUtils.getDayInYear(value); break;
                        case "DD": str = pad(DateUtils.getDayInYear(value), 3); break;
                        case "w": str = DateUtils.getWeekInYear(value); break;
                        case "ww": str = pad(DateUtils.getWeekInYear(value), 2); break;
                        case "W": str = DateUtils.getWeekInMonth(value); break;
                        case "M": str = value.getMonth() + 1; break;
                        case "MM": str = pad(value.getMonth() + 1, 2); break;
                        case "MMM": str = __(DateUtils.MONTHS[value.getMonth()].substr(0, 3) + "."); break;
                        case "MMMM": str = __(DateUtils.MONTHS[value.getMonth()]); break;
                        case "y": str = value.getFullYear() % 100; break;
                        case "yy": str = pad(value.getFullYear() % 100, 2); break;
                        case "yyyy": str = value.getFullYear(); break;
                        case "u": str = value.getDay() || 7; break;
                        case "F": str = DateUtils.getWeekCountInMonth(value); break;
                    }

                    return str.toString();
                });
            }

            this.value(formattedValue);
        }
    });

    // compact months in english don't have the dot suffix
    DOM.importStrings("en", DateUtils.MONTHS.reduce((memo, month) => {
        var shortMonth = month.slice(0, 3);

        memo[shortMonth + "."] = shortMonth;

        return memo;
    }, {}));
}(window.DOM, {
    DAYS: "Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),
    MONTHS: "January February March April May June July August September October November December".split(" "),
    getWeekInYear(d) {
        d = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()));
        // set to nearest thursday: current date + 4 - current day number
        // make sunday's day number 7
        d.setUTCDate(d.getUTCDate() + 4 - (d.getUTCDay() || 7));
        var yearStart = Date.UTC(d.getUTCFullYear(), 0, 1);
        // calculate full weeks to nearest thursday
        return Math.ceil((1 + (d - yearStart) / 86400000) / 7);
    },
    getWeekInMonth(d) {
        var firstWeekday = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), 1)).getUTCDay();
        var offsetDate = d.getUTCDate() + firstWeekday - 1;
        return 1 + Math.floor(offsetDate / 7);
    },
    getWeekCountInMonth(d) {
        return Math.ceil(d.getUTCDate() / 7);
    },
    getDayInYear(d) {
        var beginOfYear = Date.UTC(d.getUTCFullYear(), 0, 1);
        var millisBetween = d.getTime() - beginOfYear;
        return Math.floor(1 + millisBetween / 86400000);
    }
}));
<commit_msg>simplify implementation<commit_after>(function(DOM, DateUtils) {
    "use strict";

    var __ = DOM.__;
    var pad = (num, maxlen) => maxlen === 1 ? num : ("00" + num).slice(-maxlen);

    DOM.extend("time[is=local-time]", {
        constructor() {
            this.on("change", this._changeValue.bind(this));

            this._changeValue();
        },
        _changeValue() {
            var datetimeText = this.get("datetime");

            if (!datetimeText) return;

            var value = new Date(datetimeText),
                formattedValue = "";

            if (!value.getTime()) {
                formattedValue = value.toString();
            } else {
                var formatString = this.get("data-format");
                // use "E, dd MMM yyyy H:mm:ss" as default value
                if (!formatString) formatString = "E, dd MMM yyyy H:mm:ss";

                formattedValue = formatString.replace(/\w+/g, (str) => {
                    switch (str) {
                        case "H":
                        case "HH":
                            str = pad(value.getHours(), str.length);
                            break;

                        case "h":
                        case "hh":
                            str = pad(value.getHours() % 12 || 12, str.length);
                            break;

                        case "m":
                        case "mm":
                            str = pad(value.getMinutes(), str.length);
                            break;

                        case "s":
                        case "ss":
                            str = pad(value.getSeconds(), str.length);
                            break;

                        case "d":
                        case "dd":
                            str = pad(value.getDate(), str.length);
                            break;

                        case "E":
                            str = __(DateUtils.DAYS[value.getDay()].slice(0, 2));
                            break;

                        case "EE":
                            str = __(DateUtils.DAYS[value.getDay()]);
                            break;

                        case "D":
                        case "DD":
                            str = pad(DateUtils.getDayInYear(value), str.length === 1 ? 1 : 3);
                            break;

                        case "w":
                        case "ww":
                            str = pad(DateUtils.getWeekInYear(value), str.length);
                            break;

                        case "W":
                            str = DateUtils.getWeekInMonth(value);
                            break;

                        case "M":
                        case "MM":
                            str = pad(value.getMonth() + 1, str.length);
                            break;

                        case "MMM":
                            str = __(DateUtils.MONTHS[value.getMonth()].substr(0, 3) + ".");
                            break;

                        case "MMMM":
                            str = __(DateUtils.MONTHS[value.getMonth()]);
                            break;

                        case "y":
                        case "yy":
                            str = pad(value.getFullYear() % 100, str.length);
                            break;

                        case "yyyy":
                            str = value.getFullYear();
                            break;

                        case "u":
                            str = value.getDay() || 7;
                            break;

                        case "F":
                            str = DateUtils.getWeekCountInMonth(value);
                            break;
                    }

                    return str.toString();
                });
            }

            this.value(formattedValue);
        }
    });

    // compact months in english don't have the dot suffix
    DOM.importStrings("en", DateUtils.MONTHS.reduce((memo, month) => {
        var shortMonth = month.slice(0, 3);

        memo[shortMonth + "."] = shortMonth;

        return memo;
    }, {}));
}(window.DOM, {
    DAYS: "Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),
    MONTHS: "January February March April May June July August September October November December".split(" "),
    getWeekInYear(d) {
        d = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()));
        // set to nearest thursday: current date + 4 - current day number
        // make sunday's day number 7
        d.setUTCDate(d.getUTCDate() + 4 - (d.getUTCDay() || 7));
        var yearStart = Date.UTC(d.getUTCFullYear(), 0, 1);
        // calculate full weeks to nearest thursday
        return Math.ceil((1 + (d - yearStart) / 86400000) / 7);
    },
    getWeekInMonth(d) {
        var firstWeekday = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), 1)).getUTCDay();
        var offsetDate = d.getUTCDate() + firstWeekday - 1;
        return 1 + Math.floor(offsetDate / 7);
    },
    getWeekCountInMonth(d) {
        return Math.ceil(d.getUTCDate() / 7);
    },
    getDayInYear(d) {
        var beginOfYear = Date.UTC(d.getUTCFullYear(), 0, 1);
        var millisBetween = d.getTime() - beginOfYear;
        return Math.floor(1 + millisBetween / 86400000);
    }
}));
<|endoftext|>


<commit_before>(function() {
	// All known comparison-operators.
	// Please note that operators have to get more specific towards the end of
	// the array, an operator may not be containd by another that comes before
	// it. Negative example: ['=#=', '#=']
	var operators = ['=', '!=', '>', '<', '>=', '<=', '%=', '*='];
	// All Processwire-FormBuilder input-fields as jQuery array.
	var $fields = $('.Inputfield');

	// Structure this script uses to connect the field-relationships.
	var struct = {};
	// Whether to animate changes in visibility. This is not an option! Do not
	// change this value unless you know what you are doing!
	var usesAnimation = false;

	// Evaluates two given values using a comparison-operator.
	//
	// operator: String that can be found in the `operators` array.
	// v0: String extracted from the live HTML input/textarea/select field.
	// v1: String specified in the Processwire backend.
	//
	// returns: bool: `true` if the field with the value `v0` should be visible.
	function evaluateOperatorWithValues(operator, v0, v1) {
		switch (operator) {
		case '=': // is equal to
			return v0 == v1;
		case '!=': // is not equal to
			return v0 != v1;
		case '>': // is greater than
			return parseFloat(v0) > parseFloat(v1);
		case '<': // is less than
			return parseFloat(v0) < parseFloat(v1);
		case '>=': // is greater than or equal to
			return parseFloat(v0) >= parseFloat(v1);
		case '<=': // is less than or equal to
			return parseFloat(v0) <= parseFloat(v1);
		case '%=': // contains substring
		case '*=': // contains substring
			return v0.indexOf(v1) !== -1;
		default:
			console.error('The operator “'+operator+'” is not implemented in evaluateOperatorWithValues().');
		}
	}

	// Returns a value based on an field.
	function comparableValueForField(field) {
		var object = field.input;
		var value;

		if (object.tagName === 'SELECT') {
			// <select>: value of selected option
			value = object.options[object.selectedIndex].value || '';
		} else if (object.tagName === 'INPUT' && object.type === 'checkbox') {
			// <input type=checkbox>: 1 for checked, 0 for unchecked
			value = object.checked ? '1' : '0';
		} else if (object.tagName === 'INPUT' && object.type === 'radio') {
			// <input type=radio>: value of the selected input or ''
			var checked = document.querySelector('input[name='+object.name+']:checked');
			value = checked ? checked.value : '';
		} else {
			// <input>, <textarea>, etc.: value of the object
			value = object.value || '';
		}

		return value;
	}

	// Applies all conditions of a field to that field. This results in either
	// showing or hiding the field. Conditions are combined using the AND
	// operator, so they all have to evaluate to `true` to show the field.
	//
	// field: A field taken from the `struct` object.
	function applyConditions(field) {
		var show = true;

		for (var i = 0; i < field.conditions.length; i++) {
			var condition = field.conditions[i];
			var ref = struct[condition.ref];

			show &= ref.visible;
			show &= evaluateOperatorWithValues(
				condition.operator,
				comparableValueForField(ref),
				condition.value
			);
		}

		var $wrapper = $(field.wrapper);

		if (show) {
			$wrapper[(usesAnimation) ? 'slideDown' : 'show']();
			$wrapper.removeClass('fieldwire-hidden');
			field.$inputs.prop('disabled', false);
			field.visible = true;
		} else {
			$wrapper[(usesAnimation) ? 'slideUp' : 'hide']();
			$wrapper.addClass('fieldwire-hidden');
			field.$inputs.prop('disabled', true);
			field.visible = false;
		}

		// Notify all dependent fields of this change.
		evalueateDependents(field.wrapper.id);
	}

	// Evaluates the conditions for all fields that depend on a given field.
	// This function intentionally does not take a field object directly so
	// it always uses the most up-to-date version of a field.
	//
	// fieldId: The unique identifier used in the `struct` object.
	function evalueateDependents(fieldId) {
		var field = struct[fieldId];

		for (var i = 0; i < field.dependents.length; i++) {
			applyConditions(struct[field.dependents[i]]);
		}
	}

	// Create the basic `struct` structure.
	$fields.each(function() {
		var wrapper = this;
		// collect “input-like” elements
		var $inputs = $(this).find('input,textarea,select');

		struct[this.id] = {
			// the HTML node of the field
			wrapper: wrapper,
			// the HTML node of the first “input-like” element
			input: $inputs.get(0),
			// all “input-like” elements as a jQuery collection
			$inputs: $inputs,
			// this list will be filled after this $.each loop
			dependents: [],
			// fields are – by default – visible
			visible: true,
			// the condition as a string, empty string for no condition
			showIf: $(this).data('showIf') || ''
		};

		// listen for opportunities to reevaluate all dependent fields
		$inputs.on('input change blur', function() {
			usesAnimation = true;
			evalueateDependents(wrapper.id);
		});
	});

	// Add the dependencies to `struct` as well as the conditions.
	$fields.each(function() {
		// example: 'key=value,age>18'
		var showIf = struct[this.id].showIf;
		// example: ["key=value", "age>18"]
		var rawConditions = showIf.split(',');
		var conditions = [];

		for (var i = 0; i < rawConditions.length; i++) {
			var rawCondition = rawConditions[i];
			var operator;

			// find the matching operator
			for (var index in operators) {
				if (rawCondition.split(operators[index]).length === 2) {
					operator = operators[index];
				} else { continue; }
			}

			if (operator === undefined) {
				// no operator for this condition
				struct[this.id].conditions = [];
				continue;
			}

			// example: ["fieldname", "value"] or ["fieldname.count", "value"]
			var splits = rawCondition.split(operator);
			// example: ["fieldname"] or ["fieldname", "count"]
			var lhs = splits[0].split('.');
			var fieldname = lhs[0].trim();

			conditions.push({
				// id of the filed this condition depends on (v0)
				ref: 'wrap_Inputfield_'+fieldname,
				// the operator used to compare the value of `ref` to `value`
				operator: operator,
				// the comparison-value defined in the Processwire backend (v1)
				value: splits[1].replace(/^\s*'?(.*)'\s*$/, '$1'),
				modifier: lhs[1] || null
			});

			// add this field as dependent to `conditions.ref`
			struct['wrap_Inputfield_'+fieldname].dependents.push(this.id);
		}

		struct[this.id].conditions = conditions;

		applyConditions(struct[this.id]);
	});
}());<commit_msg>Remove Unnecessary Semicolons<commit_after>(function() {
	// All known comparison-operators.
	// Please note that operators have to get more specific towards the end of
	// the array, an operator may not be containd by another that comes before
	// it. Negative example: ['=#=', '#=']
	var operators = ['=', '!=', '>', '<', '>=', '<=', '%=', '*=']
	// All Processwire-FormBuilder input-fields as jQuery array.
	var $fields = $('.Inputfield')

	// Structure this script uses to connect the field-relationships.
	var struct = {}
	// Whether to animate changes in visibility. This is not an option! Do not
	// change this value unless you know what you are doing!
	var usesAnimation = false

	// Evaluates two given values using a comparison-operator.
	//
	// operator: String that can be found in the `operators` array.
	// v0: String extracted from the live HTML input/textarea/select field.
	// v1: String specified in the Processwire backend.
	//
	// returns: bool: `true` if the field with the value `v0` should be visible.
	function evaluateOperatorWithValues(operator, v0, v1) {
		switch (operator) {
		case '=': // is equal to
			return v0 == v1
		case '!=': // is not equal to
			return v0 != v1
		case '>': // is greater than
			return parseFloat(v0) > parseFloat(v1)
		case '<': // is less than
			return parseFloat(v0) < parseFloat(v1)
		case '>=': // is greater than or equal to
			return parseFloat(v0) >= parseFloat(v1)
		case '<=': // is less than or equal to
			return parseFloat(v0) <= parseFloat(v1)
		case '%=': // contains substring
		case '*=': // contains substring
			return v0.indexOf(v1) !== -1
		default:
			console.error('The operator “'+operator+'” is not implemented in evaluateOperatorWithValues().')
		}
	}

	// Returns a value based on an field.
	function comparableValueForField(field) {
		var object = field.input
		var value

		if (object.tagName === 'SELECT') {
			// <select>: value of selected option
			value = object.options[object.selectedIndex].value || ''
		} else if (object.tagName === 'INPUT' && object.type === 'checkbox') {
			// <input type=checkbox>: 1 for checked, 0 for unchecked
			value = object.checked ? '1' : '0'
		} else if (object.tagName === 'INPUT' && object.type === 'radio') {
			// <input type=radio>: value of the selected input or ''
			var checked = document.querySelector('input[name='+object.name+']:checked')
			value = checked ? checked.value : ''
		} else {
			// <input>, <textarea>, etc.: value of the object
			value = object.value || ''
		}

		return value
	}

	// Applies all conditions of a field to that field. This results in either
	// showing or hiding the field. Conditions are combined using the AND
	// operator, so they all have to evaluate to `true` to show the field.
	//
	// field: A field taken from the `struct` object.
	function applyConditions(field) {
		var show = true

		for (var i = 0; i < field.conditions.length; i++) {
			var condition = field.conditions[i]
			var ref = struct[condition.ref]

			show &= ref.visible
			show &= evaluateOperatorWithValues(
				condition.operator,
				comparableValueForField(ref),
				condition.value
			)
		}

		var $wrapper = $(field.wrapper)

		if (show) {
			$wrapper[(usesAnimation) ? 'slideDown' : 'show']()
			$wrapper.removeClass('fieldwire-hidden')
			field.$inputs.prop('disabled', false)
			field.visible = true
		} else {
			$wrapper[(usesAnimation) ? 'slideUp' : 'hide']()
			$wrapper.addClass('fieldwire-hidden')
			field.$inputs.prop('disabled', true)
			field.visible = false
		}

		// Notify all dependent fields of this change.
		evalueateDependents(field.wrapper.id)
	}

	// Evaluates the conditions for all fields that depend on a given field.
	// This function intentionally does not take a field object directly so
	// it always uses the most up-to-date version of a field.
	//
	// fieldId: The unique identifier used in the `struct` object.
	function evalueateDependents(fieldId) {
		var field = struct[fieldId]

		for (var i = 0; i < field.dependents.length; i++) {
			applyConditions(struct[field.dependents[i]])
		}
	}

	// Create the basic `struct` structure.
	$fields.each(function() {
		var wrapper = this
		// collect “input-like” elements
		var $inputs = $(this).find('input,textarea,select')

		struct[this.id] = {
			// the HTML node of the field
			wrapper: wrapper,
			// the HTML node of the first “input-like” element
			input: $inputs.get(0),
			// all “input-like” elements as a jQuery collection
			$inputs: $inputs,
			// this list will be filled after this $.each loop
			dependents: [],
			// fields are – by default – visible
			visible: true,
			// the condition as a string, empty string for no condition
			showIf: $(this).data('showIf') || ''
		}

		// listen for opportunities to reevaluate all dependent fields
		$inputs.on('input change blur', function() {
			usesAnimation = true
			evalueateDependents(wrapper.id)
		})
	})

	// Add the dependencies to `struct` as well as the conditions.
	$fields.each(function() {
		// example: 'key=value,age>18'
		var showIf = struct[this.id].showIf
		// example: ["key=value", "age>18"]
		var rawConditions = showIf.split(',')
		var conditions = []

		for (var i = 0; i < rawConditions.length; i++) {
			var rawCondition = rawConditions[i]
			var operator

			// find the matching operator
			for (var index in operators) {
				if (rawCondition.split(operators[index]).length === 2) {
					operator = operators[index]
				} else { continue }
			}

			if (operator === undefined) {
				// no operator for this condition
				struct[this.id].conditions = []
				continue
			}

			// example: ["fieldname", "value"] or ["fieldname.count", "value"]
			var splits = rawCondition.split(operator)
			// example: ["fieldname"] or ["fieldname", "count"]
			var lhs = splits[0].split('.')
			var fieldname = lhs[0].trim()

			conditions.push({
				// id of the filed this condition depends on (v0)
				ref: 'wrap_Inputfield_'+fieldname,
				// the operator used to compare the value of `ref` to `value`
				operator: operator,
				// the comparison-value defined in the Processwire backend (v1)
				value: splits[1].replace(/^\s*'?(.*)'\s*$/, '$1'),
				modifier: lhs[1] || null
			})

			// add this field as dependent to `conditions.ref`
			struct['wrap_Inputfield_'+fieldname].dependents.push(this.id)
		}

		struct[this.id].conditions = conditions

		applyConditions(struct[this.id])
	})
}())<|endoftext|>


<commit_before>// Accessory Page JS
function clearTabContent(tab){
	tab.innerText = '';
}

function getJSON(url, callback) {
    const xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);
    xhr.responseType = 'json';
    xhr.onload = () => {
        const status = xhr.status;
        if (status === 200) {
            callback(null, xhr.response);
        } else {
            callback(status);
        }
    };
    xhr.send(null);
}

function createHTML(data) {
	const container = document.createElement('div');

	const tabTitle = document.createElement('span');
	tabTitle.className = 'product-title';
	tabTitle.innerText = data.header;
	container.append(tabTitle);

	const ulElement = document.createElement('ul');
	ulElement.className = 'accessorytab';

	// for loop start point
	for(let i = 0; i < data.items.length; i++) {
	let cardLink = document.createElement('a');
	cardLink.target='_blank';
	cardLink.href = data.items[i].itemLink;

	let liElement = document.createElement('li');
	liElement.className = 'accessorytab';

	let liImage = document.createElement('img');
	liImage.src = data.items[i].itemImg;
	liElement.append(liImage);
	liElement.append(data.items[i].itemName);

	cardLink.append(liElement);
	ulElement.append(cardLink);
	}
	// for loop end point

	container.append(ulElement);
	return container;
}

const accessoryTabContent = document.querySelector('#Things') || document.querySelector('#Accessories');

if(accessoryTabContent){
	let tabContent = accessoryTabContent.innerText;
	tabContent = tabContent.split('.')[1];
	tabContent = tabContent.split('%%')[0];
	console.log(tabContent);

	switch(tabContent) {
		case 'LEDRopeLightAccessories':
			console.log('rope light accessories');
			const requestURL = 'http://www.affordablequalitylighting.com/template/LEDRopeLightAccessories.json';
			getJSON(requestURL, (error, data) => {
				clearTabContent(accessoryTabContent);
				console.log(data);
				const newContent = createHTML(data);
				accessoryTabContent.append(newContent);
			});
			break;
		case 'OutdoorAccessories':
			console.log('outdoor accessories');
			const requestURL = 'http://www.affordablequalitylighting.com/template/outdoorAccessories.json';
			getJSON(requestURL, (error, data) => {
				clearTabContent(accessoryTabContent);
				console.log(data);

				const newContent = createHTML(data);
				console.log(newContent);
				accessoryTabContent.append(newContent);
			});
			break;
		case '':
			console.log('underwater accessories');
			break;
		case '12VRopeLightAccessories':
			console.log('low voltage rope light accessories');
			break;
		default:
			console.log('no accessories');
	}
}
<commit_msg>added links to accessory tab content for snippet replacement<commit_after>// Accessory Page JS
function clearTabContent(tab){
	tab.innerText = '';
}

function getJSON(url, callback) {
    const xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);
    xhr.responseType = 'json';
    xhr.onload = () => {
        const status = xhr.status;
        if (status === 200) {
            callback(null, xhr.response);
        } else {
            callback(status);
        }
    };
    xhr.send(null);
}

function createHTML(data) {
	const container = document.createElement('div');

	const tabTitle = document.createElement('span');
	tabTitle.className = 'product-title';
	tabTitle.innerText = data.header;
	container.append(tabTitle);

	const ulElement = document.createElement('ul');
	ulElement.className = 'accessorytab';

	// for loop start point
	for(let i = 0; i < data.items.length; i++) {
	let cardLink = document.createElement('a');
	cardLink.target='_blank';
	cardLink.href = data.items[i].itemLink;

	let liElement = document.createElement('li');
	liElement.className = 'accessorytab';

	let liImage = document.createElement('img');
	liImage.src = data.items[i].itemImg;
	liElement.append(liImage);
	liElement.append(data.items[i].itemName);

	cardLink.append(liElement);
	ulElement.append(cardLink);
	}
	// for loop end point

	container.append(ulElement);
	return container;
}

const accessoryTabContent = document.querySelector('#Things') || document.querySelector('#Accessories') || document.querySelector('#Housing');

if(accessoryTabContent){
	let tabContent = accessoryTabContent.innerText;
	tabContent = tabContent.split('.')[1];
	tabContent = tabContent.split('%%')[0];
	console.log(tabContent);
	let requestURL = '';
	switch(tabContent) {
		case 'LEDRopeLightAccessories':
			console.log('rope light accessories');
			requestURL = 'http://www.affordablequalitylighting.com/template/LEDRopeLightAccessories.json';
			getJSON(requestURL, (error, data) => {
				if (error) {
					console.log(error);
				}
				clearTabContent(accessoryTabContent);
				console.log(data);
				const newContent = createHTML(data);
				accessoryTabContent.append(newContent);
			});
			break;
		case 'OutdoorAccessories':
			console.log('outdoor accessories');
			requestURL = 'http://www.affordablequalitylighting.com/template/outdoorAccessories.json';
			getJSON(requestURL, (error, data) => {
				clearTabContent(accessoryTabContent);
				console.log(data);

				const newContent = createHTML(data);
				console.log(newContent);
				accessoryTabContent.append(newContent);
			});
			break;
		case '':
			console.log('underwater accessories');
			break;
		case '12VRopeLightAccessories':
			console.log('low voltage rope light accessories');
			break;
		case '120V4FluorescentHousings':
			requestURL = 'https://www.affordablequalitylighting.com/dav/template/120V4FluorescentHousings.json';
			getJSON(requestURL, (error, data) => {
				clearTabContent(accessoryTabContent);
				console.log(data);
				const newContent = createHTML(data);
				console.log(newContent);
				accessoryTabContent.append(newContent);
			});
			break;
		case '120V4FluorescentTrim':
			requestURL = 'http://www.affordablequalitylighting.com/template/120V4FluorescentTrims.json';
			getJSON(requestURL, (error, data) => {
				clearTabContent(accessoryTabContent);
				const newContent = createHTML(data);
				accessoryTabContent.append(newContent);
			});
			break;
		case '120V4Housing':
			console.log('120V 4 Housing');
			requestURL = 'http://www.affordablequalitylighting.com/template/120V4Housing.json';
			getJSON(requestURL, (error, data) => {
				clearTabContent(accessoryTabContent);
				const newContent = createHTML(data);
				accessoryTabContent.append(newContent);
			});
			break;
		case '120V5Housing':
			requestURL = 'http://www.affordablequalitylighting.com/template/120V5Housing.json';
			getJSON(requestURL, (error, data) => {
				clearTabContent(accessoryTabContent);
				const newContent = createHTML(data);
				accessoryTabContent.append(newContent);
			});
			break;
		case '120V6FluorescentHousing':
			requestURL = 'http://www.affordablequalitylighting.com/template/120V6FluorescentHousing.json';
			getJSON(requestURL, (error, data) => {
				clearTabContent(accessoryTabContent);
				const newContent = createHTML(data);
				accessoryTabContent.append(newContent);
			});
			break;
		default:
			console.log('no accessories');
	}
}
<|endoftext|>


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

/* eslint-disable no-unused-vars */

import React from 'react';
import { AppRegistry, AsyncStorage } from 'react-native';
import { Provider } from 'react-redux';
import { applyMiddleware, createStore } from 'redux';
import thunk from 'redux-thunk';
import { persistStore } from 'redux-persist';
import { ErrorHandler } from 'redux-persist-error-handler';
import { Client as BugsnagClient } from 'bugsnag-react-native';

import { MSupplyMobileApp } from './mSupplyMobileApp';
import { reducers } from './reducers';

const bugsnagClient = new BugsnagClient();

const store = createStore(
  reducers,
  {},
  applyMiddleware(thunk),
);

const persistedStore = persistStore(store, { blacklist: ['navigation'], storage: AsyncStorage });

function App() {
  return (
    <ErrorHandler persistedStore={persistedStore}>
      <Provider store={store}>
        <MSupplyMobileApp />
      </Provider>
    </ErrorHandler>
  );
}

AppRegistry.registerComponent('mSupplyMobile', () => App);
<commit_msg>Add clarifying comment<commit_after>/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2016
 */

/* eslint-disable no-unused-vars */

import React from 'react';
import { AppRegistry, AsyncStorage } from 'react-native';
import { Provider } from 'react-redux';
import { applyMiddleware, createStore } from 'redux';
import thunk from 'redux-thunk';
import { persistStore } from 'redux-persist';
import { ErrorHandler } from 'redux-persist-error-handler';
import { Client as BugsnagClient } from 'bugsnag-react-native';

import { MSupplyMobileApp } from './mSupplyMobileApp';
import { reducers } from './reducers';

const bugsnagClient = new BugsnagClient();

const store = createStore(
  reducers,
  {},
  applyMiddleware(thunk),
);

// Persist the redux store. We have to blacklist navigation because some of the props we pass
// around via redux are enormous, possibly infinitely nested realm objects, which can't be quickly
// serialised and persisted to AsyncStorage
const persistedStore = persistStore(store, { blacklist: ['navigation'], storage: AsyncStorage });

function App() {
  return (
    <ErrorHandler persistedStore={persistedStore}>
      <Provider store={store}>
        <MSupplyMobileApp />
      </Provider>
    </ErrorHandler>
  );
}

AppRegistry.registerComponent('mSupplyMobile', () => App);
<|endoftext|>


<commit_before>enyo.kind({
	name: "enyo.sample.ListLanguagesSample",
	kind: "FittableRows",
	classes: "list-sample-language enyo-fit",
	components: [
		{kind: "onyx.MoreToolbar", layoutKind: "FittableColumnsLayout", style: "height: 55px;", components: [
			{kind: "onyx.Button", content: "Randomize", ontap: "populateList"},
		]},
		{kind: "List", classes: "list-sample-language-list enyo-unselectable", fit: true, multiSelect: true, reorderable: true,
			onSetupItem: "setupItem", onReorder: "listReorder", onSetupReorderComponents: "setupReorderComponents", onSetupPinnedReorderComponents: "setupPinnedReorderComponents",
			onSetupSwipeItem: "setupSwipeItem", onSwipeComplete: "swipeComplete",
			components: [
				{name: "item", classes: "list-sample-language-item", components: [
					{name: "text", style: "float:left;font-size:24px;text-transform:capitalize;line-height:80px;padding-left:20px;"}
				]}
			],
			reorderComponents: [
				{name: "reorderContent", style:"background:rgba(0,0,0,0.7);margin:0px;padding:0px;", classes: "enyo-fit", components: [
					{name: "reorderTitle", tag: "h2", style: "text-align:center;color:#fff;font-size:24px;"}
				]}
			], pinnedReorderComponents: [
				{name: "pinnedReorderItem", style:"background-color:rgba(0,160,40,0.8);color:white;", classes: "enyo-fit", components: [
					{name: "pinnedReorderTitle", tag: "h2", style: "text-align:center;color:#fff;font-size:24px;"},
					{name: "dropButton", kind: "onyx.Button", ontap: "dropPinnedRow", content: "Drop", style: "width:100px;height:80px;position:absolute;top:10px;right:20px;"}
				]}
			], swipeableComponents: [
				{name: "swipeItem", style:"background-color:rgba(0,160,40,0.8);color:white;", classes: "enyo-fit", components: [
					{name: "swipeTitle", style: "font-size:30px;font-weight:bold;color:#fff;text-align:center;line-height:80px;padding:0px;margin:0px;text-transform:capitalize;"}
				]}
			]
		}
	],
	rendered: function() {
		this.inherited(arguments);
		this.populateList();
	},
	listReorder: function(inSender, inEvent) {
		var movedItem = enyo.clone(data[inEvent.reorderFrom]);
		data.splice(inEvent.reorderFrom,1);
		data.splice((inEvent.reorderTo),0,movedItem);
	},
	setupItem: function(inSender, inEvent) {
		var i = inEvent.index;
		var currentLanguage = data[i].langs[data[i].currentIndex];
		var val = data[i].val;
		var number = languages[currentLanguage][val];
		this.$.text.setContent(number);
	},
	setupReorderComponents: function(inSender, inEvent) {
		var i = inEvent.index;
		var currentLanguage = data[i].langs[data[i].currentIndex];
		var val = data[i].val;
		var number = languages[currentLanguage][val];
		this.$.reorderTitle.setContent("You are moving - "+number);
	},
	setupPinnedReorderComponents: function(inSender, inEvent) {
		var i = inEvent.index;
		var currentLanguage = data[i].langs[data[i].currentIndex];
		var val = data[i].val;
		var number = languages[currentLanguage][val];
		this.$.pinnedReorderTitle.setContent("You are moving - "+number);
	},
	//* Called when the "Drop" button is pressed on the pinned placeholder row
	dropPinnedRow: function(inSender, inEvent) {
		this.$.list.dropPinnedRow(inEvent);
	},
	setupSwipeItem: function(inSender, inEvent) {
		var i = inEvent.index;
		var newLang = (inEvent.xDirection == 1)
			? this.getNextLang(i)
			: this.getPrevLang(i);
		this.$.swipeTitle.setContent(data[i].langs[newLang]);
	},
	swipeComplete: function(inSender, inEvent) {
		var i = inEvent.index;
		data[i].currentIndex = (inEvent.xDirection == 1)
			? this.getNextLang(i)
			: this.getPrevLang(i);
		this.$.list.renderRow(i);
	},
	getNextLang: function(index) {
		var currentLang = data[index].currentIndex;
		var nextLang = currentLang + 1;
		return (nextLang >= data[index].langs.length) ? 0 : nextLang;
	},
	getPrevLang: function(index) {
		var currentLang = data[index].currentIndex;
		var prevLang = currentLang - 1;
		return (prevLang <= 0) ? data[index].langs.length - 1 : prevLang;
	},
	populateList: function() {
		this.createRandomData();
		this.$.list.setCount(10);
		this.$.list.reset();
	},
	createRandomData: function() {
		var languages = this.getLanguages();
		var langs;
		data = [];
		for(var i=0;i<10;i++) {
			langs = enyo.clone(languages);
			langs.sort(function() {return 0.5 - Math.random()});
			data.push({
				langs: langs,
				val: i,
				currentIndex: 0
			});
		}
		data.sort(function() {return 0.5 - Math.random()});
	},
	getLanguages: function() {
		var retarr = [];
		for(var lang in languages) {
			retarr.push(lang);
		}
		return retarr;
	}
});

var data = [];

var languages = {
	english: ["one",  "two",  "three", "four",    "five","six","seven","eight","nine","ten"],
	italian: ["uno",  "due",  "tre",   "quattro", "cinque","sei","sette","otto","nove","dieci"],
	spanish: ["uno",  "dos",  "tres",  "cuatro",  "cinco","seis","siete","ocho","nueve","diez"],
	german:  ["eins", "zwei", "drei",  "vier",    "fünf", "sechs", "sieben", "acht", "neun", "zehn"],
	french:  ["un",   "deux", "trois", "quatre",  "cinq", "six", "sept", "huit", "neuf", "dix"]
};
<commit_msg>Fixed issue 1757.<commit_after>enyo.kind({
	name: "enyo.sample.ListLanguagesSample",
	kind: "FittableRows",
	classes: "list-sample-language enyo-fit",
	components: [
		{kind: "onyx.MoreToolbar", layoutKind: "FittableColumnsLayout", style: "height: 55px;", components: [
			{kind: "onyx.Button", content: "Randomize", ontap: "populateList"},
		]},
		{kind: "List", classes: "list-sample-language-list enyo-unselectable", fit: true, multiSelect: true, reorderable: true,
			onSetupItem: "setupItem", onReorder: "listReorder", onSetupReorderComponents: "setupReorderComponents", onSetupPinnedReorderComponents: "setupPinnedReorderComponents",
			onSetupSwipeItem: "setupSwipeItem", onSwipeComplete: "swipeComplete",
			components: [
				{name: "item", classes: "list-sample-language-item", components: [
					{name: "text", style: "float:left;font-size:24px;text-transform:capitalize;line-height:80px;padding-left:20px;"}
				]}
			],
			reorderComponents: [
				{name: "reorderContent", style:"background:rgba(0,0,0,0.7);margin:0px;padding:0px;", classes: "enyo-fit", components: [
					{name: "reorderTitle", tag: "h2", style: "text-align:center;color:#fff;font-size:24px;"}
				]}
			], pinnedReorderComponents: [
				{name: "pinnedReorderItem", style:"background-color:rgba(0,160,40,0.8);color:white;", classes: "enyo-fit", components: [
					{name: "pinnedReorderTitle", tag: "h2", style: "text-align:center;color:#fff;font-size:24px;"},
					{name: "dropButton", kind: "onyx.Button", ontap: "dropPinnedRow", content: "Drop", style: "width:100px;height:80px;position:absolute;top:10px;right:20px;"}
				]}
			], swipeableComponents: [
				{name: "swipeItem", style:"background-color:rgba(0,160,40,0.8);color:white;", classes: "enyo-fit", components: [
					{name: "swipeTitle", style: "font-size:30px;font-weight:bold;color:#fff;text-align:center;line-height:80px;padding:0px;margin:0px;text-transform:capitalize;"}
				]}
			]
		}
	],
	rendered: function() {
		this.inherited(arguments);
		this.populateList();
	},
	listReorder: function(inSender, inEvent) {
		var movedItem = enyo.clone(data[inEvent.reorderFrom]);
		data.splice(inEvent.reorderFrom,1);
		data.splice((inEvent.reorderTo),0,movedItem);
	},
	setupItem: function(inSender, inEvent) {
		var i = inEvent.index;
		var currentLanguage = data[i].langs[data[i].currentIndex];
		var val = data[i].val;
		var number = languages[currentLanguage][val];
		this.$.text.setContent(number);
	},
	setupReorderComponents: function(inSender, inEvent) {
		var i = inEvent.index;
		var currentLanguage = data[i].langs[data[i].currentIndex];
		var val = data[i].val;
		var number = languages[currentLanguage][val];
		this.$.reorderTitle.setContent("You are moving - "+number);
	},
	setupPinnedReorderComponents: function(inSender, inEvent) {
		var i = inEvent.index;
		var currentLanguage = data[i].langs[data[i].currentIndex];
		var val = data[i].val;
		var number = languages[currentLanguage][val];
		this.$.pinnedReorderTitle.setContent("You are moving - "+number);
	},
	//* Called when the "Drop" button is pressed on the pinned placeholder row
	dropPinnedRow: function(inSender, inEvent) {
		this.$.list.dropPinnedRow(inEvent);
	},
	setupSwipeItem: function(inSender, inEvent) {
		var i = inEvent.index;
		var newLang = (inEvent.xDirection == 1)
			? this.getNextLang(i)
			: this.getPrevLang(i);
		this.$.swipeTitle.setContent(data[i].langs[newLang]);
	},
	swipeComplete: function(inSender, inEvent) {
		var i = inEvent.index;
		data[i].currentIndex = (inEvent.xDirection == 1)
			? this.getNextLang(i)
			: this.getPrevLang(i);
		this.$.list.renderRow(i);
	},
	getNextLang: function(index) {
		var currentLang = data[index].currentIndex;
		var nextLang = currentLang + 1;
		return (nextLang >= data[index].langs.length) ? 0 : nextLang;
	},
	getPrevLang: function(index) {
		var currentLang = data[index].currentIndex;
		var prevLang = currentLang - 1;
		return (prevLang < 0) ? data[index].langs.length - 1 : prevLang;
	},
	populateList: function() {
		this.createRandomData();
		this.$.list.setCount(10);
		this.$.list.reset();
	},
	createRandomData: function() {
		var languages = this.getLanguages();
		var langs;
		data = [];
		for(var i=0;i<10;i++) {
			langs = enyo.clone(languages);
			langs.sort(function() {return 0.5 - Math.random()});
			data.push({
				langs: langs,
				val: i,
				currentIndex: 0
			});
		}
		data.sort(function() {return 0.5 - Math.random()});
	},
	getLanguages: function() {
		var retarr = [];
		for(var lang in languages) {
			retarr.push(lang);
		}
		return retarr;
	}
});

var data = [];

var languages = {
	english: ["one",  "two",  "three", "four",    "five","six","seven","eight","nine","ten"],
	italian: ["uno",  "due",  "tre",   "quattro", "cinque","sei","sette","otto","nove","dieci"],
	spanish: ["uno",  "dos",  "tres",  "cuatro",  "cinco","seis","siete","ocho","nueve","diez"],
	german:  ["eins", "zwei", "drei",  "vier",    "fünf", "sechs", "sieben", "acht", "neun", "zehn"],
	french:  ["un",   "deux", "trois", "quatre",  "cinq", "six", "sept", "huit", "neuf", "dix"]
};
<|endoftext|>


<commit_before>require('dotenv').load();

const craftai = require('craft-ai').createClient;
const fs = require('fs');
const path = require('path');
const process = require('process');

var utils = require('./utils');

const ROOM1 = 'BEDROOM_1';
const ROOM2 = 'LIVING_ROOM';
const ROOM3 = 'RESTROOM';

const GENERATOR_FILTER = [ROOM1, ROOM2, ROOM3];
const GENERATOR_NAME = 'smarthome';

const LOCAL_FILE_PATH1 = path.join(__dirname, `../data/twor_${ROOM1}.json`);
const LOCAL_FILE_PATH2 = path.join(__dirname, `../data/twor_${ROOM2}.json`);
const LOCAL_FILE_PATH3 = path.join(__dirname, `../data/twor_${ROOM3}.json`);

// 0 - Create the craft client
const CRAFT_CLIENT = craftai(process.env.CRAFT_TOKEN);

// 1 - Retrieve the prepared data
utils.readData(LOCAL_FILE_PATH1)
  .then((context) => {
    const agentName = ROOM1;
    // 2 - Cleanup the mess (agent's name can't be duplicate)
    return CRAFT_CLIENT.deleteAgent(agentName)
      // 3 - Create the agent 1
      .then(() => {
        console.log(`Creating agent ${agentName}.`);
        return CRAFT_CLIENT.createAgent({
          context: {
            movement: {
              type: 'continuous'
            },
            light: {
              type: 'enum'
            },
            tz: {
              type: 'timezone'
            },
            time: {
              type: 'time_of_day'
            }
          },
          output: ['light'],
          time_quantum: 15 * 60 // 15 min
        }, agentName);
      })
      // 4 - Send the dataset's operations
      .then(() => {
        console.log(`Adding context operations for agent ${agentName}...`);
        return CRAFT_CLIENT.addAgentContextOperations(agentName, context);
      })
      .then(() => {
        console.log(`Computing the decision model for agent ${agentName} (this may take a little while)...`);
        // 5 - Compute decision from the decision tree in order to automate the light
        // Download the tree
        return CRAFT_CLIENT.getAgentDecisionTree(agentName, context[context.length - 1].timestamp, 2);
      })
      .then((tree) => {
        console.log('Decision tree computed!');
        // 6 - Get decisions
        const d1 = craftai.interpreter.decide(
          tree,
          {
            movement: 0
          },
          new craftai.Time('2010-01-04T01:30:00+09:00')
        );
        console.log(`Decision taken:\n- The light is ${d1.output.light.predicted_value} when there is no movement at 1:30AM.`);
        {
          const d = craftai.interpreter.decide(
            tree,
            {
              movement: 0
            },
            new craftai.Time('2010-01-04T08:58:00+09:00')
          );
          console.log(`- The light is ${d.output.light.predicted_value} when there is no movement at 8:58AM.`);
        }
        {
          const d = craftai.interpreter.decide(
            tree,
            {
              movement: 0
            },
            new craftai.Time('2010-01-04T09:42:00+09:00')
          );
          console.log(`- The light is ${d.output.light.predicted_value} when there is no movement at 9:42AM.`);
        }
        {
          const d = craftai.interpreter.decide(
            tree,
            {
              movement: 2
            },
            new craftai.Time('2010-01-04T09:42:00+09:00')
          );
          console.log(`- The light is ${d.output.light.predicted_value} when there is some movement at 9:42AM.`);
        }
        {
          const d = craftai.interpreter.decide(
            tree,
            {
              movement: 2
            },
            new craftai.Time('2010-01-04T17:03:00+09:00')
          );
          console.log(`- The light is ${d.output.light.predicted_value} when there is some movement at 5:03PM.`);
        }
        {
          const d = craftai.interpreter.decide(
            tree,
            {
              movement: 2
            },
            new craftai.Time('2010-01-04T20:55:00+09:00')
          );
          console.log(`- The light is ${d.output.light.predicted_value} when there is some movement at 8:55PM.`);
        }
        {
          const d = craftai.interpreter.decide(
            tree,
            {
              movement: 2
            },
            new craftai.Time('2010-01-04T22:07:00+09:00')
          );
          console.log(`- The light is ${d.output.light.predicted_value} when there is some movement at 10:07PM.`);
        }
        {
          const d = craftai.interpreter.decide(
            tree,
            {
              movement: 10
            },
            new craftai.Time('2010-01-04T09:42:00+09:00')
          );
          console.log(`- The light is ${d.output.light.predicted_value} when there is a lot of movement at 9:42AM.`);
        }
        {
          const d = craftai.interpreter.decide(
            tree,
            {
              movement: 10
            },
            new craftai.Time('2010-01-04T02:17:00+09:00')
          );
          console.log(`- The light is ${d.output.light.predicted_value} when there is a lot of movement at 2:17AM.`);
        }
      })
      .then(() => {
        const deleteBulkPayload = [
          { id: ROOM1 },
          { id: ROOM2 },
          { id: ROOM3 }
        ];
        return CRAFT_CLIENT.deleteAgentBulk(deleteBulkPayload);
      })
      // 7 - Create Agent 1, 2 and 3
      .then(() => utils.readData(LOCAL_FILE_PATH1))
      .then((context_1) => {
        operations_agent_1 = utils.prepareData(context_1, ROOM1);
        return utils.readData(LOCAL_FILE_PATH2);
      })
      .then((context_2) => {
        operations_agent_2 = utils.prepareData(context_2, ROOM2);
        return utils.readData(LOCAL_FILE_PATH3);
      })
      .then((context_3) => {
        operations_agent_3 = utils.prepareData(context_3, ROOM3);
        const configuration = {
          context: {
            movement: {
              type: 'continuous'
            },
            stateChange: {
              type: 'enum'
            },
            room: {
              type: 'enum'
            },
            tz: {
              type: 'timezone'
            },
            time: {
              type: 'time_of_day'
            }
          },
          output: ['stateChange'],
          time_quantum: 15 * 60 // 15 min
        };
        const createBulkPayload = [
          { id: ROOM1, configuration: configuration },
          { id: ROOM2, configuration: configuration },
          { id: ROOM3, configuration: configuration }
        ];
        console.log(`Creating agents ${ROOM1}, ${ROOM2} and ${ROOM3}.`);
        return CRAFT_CLIENT.createAgentBulk(createBulkPayload)
      })
      .then(() => {
        const contextOperationBulkPayload = [
          { id: ROOM1, operations: operations_agent_1 },
          { id: ROOM2, operations: operations_agent_2 },
          { id: ROOM3, operations: operations_agent_3 }
        ];
        console.log(`Adding context operations for agents ${ROOM1}, ${ROOM2} and ${ROOM3}.`);
        return CRAFT_CLIENT.addAgentContextOperationsBulk(contextOperationBulkPayload)
      })
      .then(() => {
        const GENERATOR_CONFIGURATION = {
          context: {
            stateChange: {
              type: 'enum'
            },
            room: {
              type: 'enum'
            },
            tz: {
              type: 'timezone'
            },
            time: {
              type: 'time_of_day',
              is_generated: true
            }
          },
          output: [
            "stateChange"
          ],
          learning_period: 1500000,
          tree_max_operations: 15000,
          operations_as_events: true,
          filter: GENERATOR_FILTER
        };
        console.log(`Creating generator ${GENERATOR_NAME}.`);
        // 8 - Create generator
        return CRAFT_CLIENT.createGenerator(GENERATOR_CONFIGURATION, GENERATOR_NAME);
      })
      .then(() => {
        console.log(`Computing the decision model for generator ${GENERATOR_NAME} (this may take a little while)...`);
        // 9 - Compute decision from the decision tree in order to automate the light
        // Download the tree
        return CRAFT_CLIENT.getGeneratorDecisionTree(GENERATOR_NAME, context[context.length - 1].timestamp);
      })
      .then((tree) => {
        console.log('Generator decision tree computed!');
        // 10 - Get decisions
        {
          const d = craftai.interpreter.decide(
            tree,
            {
              room: ROOM1
            },
            new craftai.Time('2010-01-04T01:30:00+09:00')
          );
          console.log(`- A change of state ${d.output.stateChange.predicted_value} is expected in the bedroom at 1:30AM.`);
        }
        {
          const d = craftai.interpreter.decide(
            tree,
            {
              room: ROOM2
            },
            new craftai.Time('2010-01-04T08:58:00+09:00')
          );
          console.log(`- A change of state ${d.output.stateChange.predicted_value} is expected in the living room at 8:58AM.`);
        }
        {
          const d = craftai.interpreter.decide(
            tree,
            {
              room: ROOM3
            },
            new craftai.Time('2010-01-04T09:42:00+09:00')
          );
          console.log(`- A change of state ${d.output.stateChange.predicted_value} is expected in the restroom at 9:42AM.`);
        }
        {
          const d = craftai.interpreter.decide(
            tree,
            {
              room: ROOM1
            },
            new craftai.Time('2010-01-08T02:17:00+09:00')
          );
          console.log(`- A change of state ${d.output.stateChange.predicted_value} is expected in the bedroom at 2:17AM.`);
        }
      })
  })
  .catch((error) => {
    console.log('Error!', error);
    process.exit(1);
  });
<commit_msg>Update src/main.js<commit_after>require('dotenv').load();

const craftai = require('craft-ai').createClient;
const fs = require('fs');
const path = require('path');
const process = require('process');

var utils = require('./utils');

const ROOM1 = 'BEDROOM_1';
const ROOM2 = 'LIVING_ROOM';
const ROOM3 = 'RESTROOM';

const GENERATOR_FILTER = [ROOM1, ROOM2, ROOM3];
const GENERATOR_NAME = 'smarthome';

const LOCAL_FILE_PATH1 = path.join(__dirname, `../data/twor_${ROOM1}.json`);
const LOCAL_FILE_PATH2 = path.join(__dirname, `../data/twor_${ROOM2}.json`);
const LOCAL_FILE_PATH3 = path.join(__dirname, `../data/twor_${ROOM3}.json`);

// 0 - Create the craft client
const CRAFT_CLIENT = craftai(process.env.CRAFT_TOKEN);

// 1 - Retrieve the prepared data
utils.readData(LOCAL_FILE_PATH1)
  .then((context) => {
    const agentName = ROOM1;
    // 2 - Cleanup the mess (agent's name can't be duplicate)
    return CRAFT_CLIENT.deleteAgent(agentName)
      // 3 - Create the agent 1
      .then(() => {
        console.log(`Creating agent ${agentName}.`);
        return CRAFT_CLIENT.createAgent({
          context: {
            movement: {
              type: 'continuous'
            },
            light: {
              type: 'enum'
            },
            tz: {
              type: 'timezone'
            },
            time: {
              type: 'time_of_day'
            }
          },
          output: ['light'],
          time_quantum: 15 * 60 // 15 min
        }, agentName);
      })
      // 4 - Send the dataset's operations
      .then(() => {
        console.log(`Adding context operations for agent ${agentName}...`);
        return CRAFT_CLIENT.addAgentContextOperations(agentName, context);
      })
      .then(() => {
        console.log(`Computing the decision model for agent ${agentName} (this may take a little while)...`);
        // 5 - Compute decision from the decision tree in order to automate the light
        // Download the tree
        return CRAFT_CLIENT.getAgentDecisionTree(agentName, context[context.length - 1].timestamp, 2);
      })
      .then((tree) => {
        console.log('Decision tree computed!');
        // 6 - Get decisions
        const d1 = craftai.interpreter.decide(
          tree,
          {
            movement: 0
          },
          new craftai.Time('2010-01-04T01:30:00+09:00')
        );
        console.log(`Decision taken:\n- The light is ${d1.output.light.predicted_value} when there is no movement at 1:30AM.`);
        const d2 = craftai.interpreter.decide(
          tree,
          {
            movement: 0
          },
          new craftai.Time('2010-01-04T08:58:00+09:00')
        );
        console.log(`- The light is ${d2.output.light.predicted_value} when there is no movement at 8:58AM.`);
        {
          const d = craftai.interpreter.decide(
            tree,
            {
              movement: 0
            },
            new craftai.Time('2010-01-04T09:42:00+09:00')
          );
          console.log(`- The light is ${d.output.light.predicted_value} when there is no movement at 9:42AM.`);
        }
        {
          const d = craftai.interpreter.decide(
            tree,
            {
              movement: 2
            },
            new craftai.Time('2010-01-04T09:42:00+09:00')
          );
          console.log(`- The light is ${d.output.light.predicted_value} when there is some movement at 9:42AM.`);
        }
        {
          const d = craftai.interpreter.decide(
            tree,
            {
              movement: 2
            },
            new craftai.Time('2010-01-04T17:03:00+09:00')
          );
          console.log(`- The light is ${d.output.light.predicted_value} when there is some movement at 5:03PM.`);
        }
        {
          const d = craftai.interpreter.decide(
            tree,
            {
              movement: 2
            },
            new craftai.Time('2010-01-04T20:55:00+09:00')
          );
          console.log(`- The light is ${d.output.light.predicted_value} when there is some movement at 8:55PM.`);
        }
        {
          const d = craftai.interpreter.decide(
            tree,
            {
              movement: 2
            },
            new craftai.Time('2010-01-04T22:07:00+09:00')
          );
          console.log(`- The light is ${d.output.light.predicted_value} when there is some movement at 10:07PM.`);
        }
        {
          const d = craftai.interpreter.decide(
            tree,
            {
              movement: 10
            },
            new craftai.Time('2010-01-04T09:42:00+09:00')
          );
          console.log(`- The light is ${d.output.light.predicted_value} when there is a lot of movement at 9:42AM.`);
        }
        {
          const d = craftai.interpreter.decide(
            tree,
            {
              movement: 10
            },
            new craftai.Time('2010-01-04T02:17:00+09:00')
          );
          console.log(`- The light is ${d.output.light.predicted_value} when there is a lot of movement at 2:17AM.`);
        }
      })
      .then(() => {
        const deleteBulkPayload = [
          { id: ROOM1 },
          { id: ROOM2 },
          { id: ROOM3 }
        ];
        return CRAFT_CLIENT.deleteAgentBulk(deleteBulkPayload);
      })
      // 7 - Create Agent 1, 2 and 3
      .then(() => utils.readData(LOCAL_FILE_PATH1))
      .then((context_1) => {
        operations_agent_1 = utils.prepareData(context_1, ROOM1);
        return utils.readData(LOCAL_FILE_PATH2);
      })
      .then((context_2) => {
        operations_agent_2 = utils.prepareData(context_2, ROOM2);
        return utils.readData(LOCAL_FILE_PATH3);
      })
      .then((context_3) => {
        operations_agent_3 = utils.prepareData(context_3, ROOM3);
        const configuration = {
          context: {
            movement: {
              type: 'continuous'
            },
            stateChange: {
              type: 'enum'
            },
            room: {
              type: 'enum'
            },
            tz: {
              type: 'timezone'
            },
            time: {
              type: 'time_of_day'
            }
          },
          output: ['stateChange'],
          time_quantum: 15 * 60 // 15 min
        };
        const createBulkPayload = [
          { id: ROOM1, configuration: configuration },
          { id: ROOM2, configuration: configuration },
          { id: ROOM3, configuration: configuration }
        ];
        console.log(`Creating agents ${ROOM1}, ${ROOM2} and ${ROOM3}.`);
        return CRAFT_CLIENT.createAgentBulk(createBulkPayload)
      })
      .then(() => {
        const contextOperationBulkPayload = [
          { id: ROOM1, operations: operations_agent_1 },
          { id: ROOM2, operations: operations_agent_2 },
          { id: ROOM3, operations: operations_agent_3 }
        ];
        console.log(`Adding context operations for agents ${ROOM1}, ${ROOM2} and ${ROOM3}.`);
        return CRAFT_CLIENT.addAgentContextOperationsBulk(contextOperationBulkPayload)
      })
      .then(() => {
        const GENERATOR_CONFIGURATION = {
          context: {
            stateChange: {
              type: 'enum'
            },
            room: {
              type: 'enum'
            },
            tz: {
              type: 'timezone'
            },
            time: {
              type: 'time_of_day',
              is_generated: true
            }
          },
          output: [
            "stateChange"
          ],
          learning_period: 1500000,
          tree_max_operations: 15000,
          operations_as_events: true,
          filter: GENERATOR_FILTER
        };
        console.log(`Creating generator ${GENERATOR_NAME}.`);
        // 8 - Create generator
        return CRAFT_CLIENT.createGenerator(GENERATOR_CONFIGURATION, GENERATOR_NAME);
      })
      .then(() => {
        console.log(`Computing the decision model for generator ${GENERATOR_NAME} (this may take a little while)...`);
        // 9 - Compute decision from the decision tree in order to automate the light
        // Download the tree
        return CRAFT_CLIENT.getGeneratorDecisionTree(GENERATOR_NAME, context[context.length - 1].timestamp);
      })
      .then((tree) => {
        console.log('Generator decision tree computed!');
        // 10 - Get decisions
        {
          const d = craftai.interpreter.decide(
            tree,
            {
              room: ROOM1
            },
            new craftai.Time('2010-01-04T01:30:00+09:00')
          );
          console.log(`- A change of state ${d.output.stateChange.predicted_value} is expected in the bedroom at 1:30AM.`);
        }
        {
          const d = craftai.interpreter.decide(
            tree,
            {
              room: ROOM2
            },
            new craftai.Time('2010-01-04T08:58:00+09:00')
          );
          console.log(`- A change of state ${d.output.stateChange.predicted_value} is expected in the living room at 8:58AM.`);
        }
        {
          const d = craftai.interpreter.decide(
            tree,
            {
              room: ROOM3
            },
            new craftai.Time('2010-01-04T09:42:00+09:00')
          );
          console.log(`- A change of state ${d.output.stateChange.predicted_value} is expected in the restroom at 9:42AM.`);
        }
        {
          const d = craftai.interpreter.decide(
            tree,
            {
              room: ROOM1
            },
            new craftai.Time('2010-01-08T02:17:00+09:00')
          );
          console.log(`- A change of state ${d.output.stateChange.predicted_value} is expected in the bedroom at 2:17AM.`);
        }
      })
  })
  .catch((error) => {
    console.log('Error!', error);
    process.exit(1);
  });
<|endoftext|>