<commit_before>/*
 *  Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 *  WSO2 Inc. licenses this file to you under the Apache License,
 *  Version 2.0 (the "License"); you may not use this file except
 *  in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing,
 *  software distributed under the License is distributed on an
 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *  KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations
 *  under the License.
 *
 */
var api = {};
(function(api) {
    var log = new Log();
    var ACTION_STATE = 'state';
    var ACTION_CHANGE_STATE = 'change-state';
    var ACTION_CHECKLIST = 'checklist';
    var ACTION_UPDATE_CHECKLIST = 'update-checklist';
    var ACTION_LC_HISTORY = 'lifecycle-history';
    var ACTION_ADD_TAGS = 'add-tags';
    var ACTION_REMOVE_TAGS = 'remove-tags';
    var ACTION_RETRIEVE_TAGS = 'tags';
    var ACTION_CREATE_VERSION = 'create-version';
    var HTTP_ERROR_NOT_IMPLEMENTED = 501;
    var CONTENT_TYPE_JSON = 'application/json';
    var MSG_ERROR_NOT_IMPLEMENTED = 'The provided action is not supported by this endpoint';
    var lifecycleAPI = require('/modules/lifecycle/lifecycle-api.js').api;
    var utils = require('utils');
    var rxtModule = require('rxt');
    var es = require("store").server;
    var tagsAPI = require('/modules/tags-api.js').api;
    var assetAPI = require('/modules/asset-api.js').api;
    var utility = require('/modules/utility.js').rxt_utility();
    var exceptionModule = utils.exception;
    var constants = rxtModule.constants;
    var msg = function(code, message, data) {
        var obj = {};
        obj.code = code;
        obj.message = message;
        obj.data = data;
        return obj;
    };
    var successMsg = function(obj) {
        obj.success = true;
        return obj;
    };
    var errorMsg = function(obj) {
        obj.success = false;
        return obj;
    };
    var validateOptions = function(options) {
        if (!options.type) {
            var error = 'Unable to obtain state information without knowing the type of asset of id: ' + options.id;
            log.error(error);
            throw exceptionModule.buildExceptionObject(error, constants.STATUS_CODES.BAD_REQUEST);
        }
    };

    function validatePayload(str) {
        try {
            JSON.parse(str);
        } catch (e) {
            var message = 'Error while parsing the message payload, please send correct content';
            throw exceptionModule.buildExceptionObject(message, constants.STATUS_CODES.BAD_REQUEST);
        }
        return true;
    }

    var parseContentType = function(contentTypString) {
        var comps = contentTypString.split(';');
        return comps[0];
    };
    /**
     * Allows request data to be sent in either the request body or
     * as url encoded query parameters
     * @param  {Object} req  Request object
     * @return {Object}      An object which contains data from request body and url encoded parameters
     */
    var obtainData = function(req) {
        var data = {};
        var contentType = parseContentType(req.getContentType());
        if (contentType === CONTENT_TYPE_JSON) {
            try {
                data = req.getContent();
            } catch (e) {
                log.error('Unable to obtain content from request', e);
            }
        }
        var params = req.getAllParameters('UTF-8');
        //Mix the content with request parameters
        for (var key in params) {
            data[key] = params[key];
        }
        return data;
    };
    api.state = function(req, res, session, options) {
        if (req.getMethod() !== 'GET') {
            return errorMsg(msg(405, 'State must be retrieved using a GET'));
        }
        validateOptions(options);
        var result;
        try {
            result = lifecycleAPI.getState(options, req, res, session);
        } catch (e) {
            if (e == "Unauthorized Action - does not have permissions to view lifecycle state") {
                var errorResponse = msg(401, 'User does not have permission to view lifecycle state', e);
                errorResponse.errorContent = {};

                errorResponse.errorContent.message = 'User does not have permission to view lifecycle state';
                errorResponse.errorContent.exception = e;

                return errorMsg(errorResponse);
            } else {
                throw e;
            }
        }
        return successMsg(msg(200, 'Asset state information returned', result));
    };
    api.changeState = function(req, res, session, options) {
        var newState = null;
        var result = {};
        var data;
        var succcess;
        if (req.getMethod() !== 'POST') {
            return errorMsg(msg(405, 'State must be changed by a POST'));
        }
        data = obtainData(req);
        if (!data.nextState) {
            log.error('State change requires a nextState to be provided either as a query string or in the body of the request');
            return errorMsg(msg(400, 'State change requires a nextState to be provided either as a query string or in the body of the request'));
        }
        options.nextState = data.nextState;
        options.comment = data.comment;
        //Call the state change api

        try {
            success = lifecycleAPI.changeState(options, req, res, session);
        } catch (e) {
            throw e;
        }
        if (success) {
            //Obtain the next states
            result.newState = data.nextState;
            result.traversableStates = lifecycleAPI.traversableStates(options, req, res, session);
        }
        if (success) {
            return successMsg(msg(200, 'The assets state was changed', result));
        } else {
            return errorMsg(msg(500, 'The asset state was not changed'));
        }
    };
    api.updateCheckList = function(req, res, session, options) {
        var success;
        var body;
        if (!req.getContent() || !req.getContentType() === 'application/json') {
            var message = 'Checklist items must be sent in the body of the request and content type should be set to application/json';
            throw exceptionModule.buildExceptionObject(message, constants.STATUS_CODES.BAD_REQUEST);
        }
        body = req.getContent();
        if((typeof body) == 'string'){
            try {
                body = parse(body);
            } catch (e) {
                var message = 'Error while parsing the message payload, please send correct content';
                throw exceptionModule.buildExceptionObject(message, constants.STATUS_CODES.BAD_REQUEST);
            }
        }
        options.checkItems = body.checklist || [];
        success = lifecycleAPI.checkItems(options, req, res, session);
        if (success) {
            return successMsg(msg(200, 'The checklist was updated successfully'));
        }
        return errorMsg(msg(500, 'The checklist was not updated'));
    };
    api.lifecycleHistory = function(req, res, session, options) {
        var history = lifecycleAPI.getHistory(options, req, res, session);
        //var xmlHistoryContent = new XML(history.content);
        //var historyContent = utils.xml.convertE4XtoJSON(xmlHistoryContent)||{};
        return successMsg(msg(200, 'Lifecycle history retrieved successfully', history.item || []));
    };
    api.addTags = function(req, res, session, options) {
        var success;
        if(req.getMethod() !== 'POST'){
            return errorMsg(msg(405, 'Tags must be added by a POST'));
        }
        try {
            success = tagsAPI.addTags(req, res, session, options);
        } catch (e) {
            log.error(e);
        }
        if (success) {
            return successMsg(msg(200, 'Tags added successfully'));
        }
        return errorMsg(msg(500, 'Tags were not added'));
    };
    api.removeTags = function(req, res, session, options) {
        var success;
        if(req.getMethod() !== 'DELETE'){
            return errorMsg(msg(405, 'Tags must be removed using a DELETE'));
        }
        try {
            success = tagsAPI.removeTags(req, res, session, options);
        } catch (e) {
            log.error(e);
        }
        if (success) {
            return successMsg(msg(200, 'Tags removed successfully'));
        }
        return errorMsg(msg(500, 'Tags were not removed'));
    };
    api.tags = function(req, res, session, options) {
        var tags = [];
        var success;
        if(req.getMethod() !== 'GET'){
            return errorMsg(msg(405, 'Tags must be retrieved using a GET'));
        }
        try {
            tags = tagsAPI.tags(req,res,session,options);
            success = true;
        } catch(e){
            log.error(e);
        }
        if (success) {
            return successMsg(msg(200, 'Tags of the asset retrieved successfully', tags));
        }
        return errorMsg(msg(500, 'Tags were not retrieved'));
    };
    /**
     * api to create  a new version of the given asset
     * @param  options Object containing asset id, type, new version
     * @param  req     jaggery request
     * @param  res     jaggery response
     * @param  session  sessionId
     * @return The created asset or null if failed to create the asset
     */
    api.createVersion = function(req, res, session, options) {
        var asset;
        var createdAsset;
        var attributes;
        var assetModule = rxtModule.asset;
        var am = assetModule.createUserAssetManager(session, options.type);
        if(req.getMethod() !== 'POST'){
            return errorMsg(msg(405, 'Create version should be done using a POST'));
        }
        var content = req.getContent();
        validatePayload(content);
        try {
            data = parse(content);
            asset = am.createVersion(options, data.attributes);
            if(asset){
                 tenantId = es.current(session).tenantId;
                var registry = es.systemRegistry(tenantId);

                if(registry.registry.resourceExists('/_system/governance/store/asset_resources/'+ options.type + '/' + options.id)){
                    registry.registry.copy('/_system/governance/store/asset_resources/'+ options.type + '/' + options.id,'/_system/governance/store/asset_resources/'+ options.type + '/' + asset);
                }
                return successMsg(msg(200, 'New version created successfully.', asset));
            }
            return errorMsg(msg(500, 'New version of asset of id:'+ options.id + ' could not be created.'));

        } catch (e) {
            log.error('Asset of type: ' + options.type + ' was not created due to ' ,e);
            return errorMsg(msg(500, 'New version of asset of id :'+ options.id + ' could not be created.'));
        }
    };
    api.resolve = function(req, res, session, options) {
        var action = options.action;
        var result = errorMsg(msg(HTTP_ERROR_NOT_IMPLEMENTED, MSG_ERROR_NOT_IMPLEMENTED));
        switch (action) {
            case ACTION_STATE:
                result = api.state(req, res, session, options);
                break;
            case ACTION_CHANGE_STATE:
                result = api.changeState(req, res, session, options);
                break;
            case ACTION_UPDATE_CHECKLIST:
                result = api.updateCheckList(req, res, session, options);
                break;
            case ACTION_LC_HISTORY:
                result = api.lifecycleHistory(req, res, session, options);
                break;
            case ACTION_ADD_TAGS:
                result = api.addTags(req, res, session, options);
                break;
            case ACTION_REMOVE_TAGS:
                result = api.removeTags(req, res, session, options);
                break;
            case ACTION_RETRIEVE_TAGS:
                result = api.tags(req, res, session, options);
                break;
            case ACTION_CREATE_VERSION:
                result = api.createVersion(req, res, session, options);
                break;
            default:
                break;
        }
        return result;
    };
}(api));<commit_msg>REGISTRY-3242, Check for assert version before creating a new version,If conflict occored return with HTTP 409<commit_after>/*
 *  Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 *  WSO2 Inc. licenses this file to you under the Apache License,
 *  Version 2.0 (the "License"); you may not use this file except
 *  in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing,
 *  software distributed under the License is distributed on an
 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *  KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations
 *  under the License.
 *
 */
var api = {};
(function(api) {
    var log = new Log();
    var ACTION_STATE = 'state';
    var ACTION_CHANGE_STATE = 'change-state';
    var ACTION_CHECKLIST = 'checklist';
    var ACTION_UPDATE_CHECKLIST = 'update-checklist';
    var ACTION_LC_HISTORY = 'lifecycle-history';
    var ACTION_ADD_TAGS = 'add-tags';
    var ACTION_REMOVE_TAGS = 'remove-tags';
    var ACTION_RETRIEVE_TAGS = 'tags';
    var ACTION_CREATE_VERSION = 'create-version';
    var HTTP_ERROR_NOT_IMPLEMENTED = 501;
    var CONTENT_TYPE_JSON = 'application/json';
    var MSG_ERROR_NOT_IMPLEMENTED = 'The provided action is not supported by this endpoint';
    var lifecycleAPI = require('/modules/lifecycle/lifecycle-api.js').api;
    var utils = require('utils');
    var rxtModule = require('rxt');
    var es = require("store").server;
    var tagsAPI = require('/modules/tags-api.js').api;
    var assetAPI = require('/modules/asset-api.js').api;
    var utility = require('/modules/utility.js').rxt_utility();
    var exceptionModule = utils.exception;
    var constants = rxtModule.constants;
    var msg = function(code, message, data) {
        var obj = {};
        obj.code = code;
        obj.message = message;
        obj.data = data;
        return obj;
    };
    var successMsg = function(obj) {
        obj.success = true;
        return obj;
    };
    var errorMsg = function(obj) {
        obj.success = false;
        return obj;
    };
    var validateOptions = function(options) {
        if (!options.type) {
            var error = 'Unable to obtain state information without knowing the type of asset of id: ' + options.id;
            log.error(error);
            throw exceptionModule.buildExceptionObject(error, constants.STATUS_CODES.BAD_REQUEST);
        }
    };

    function validatePayload(str) {
        try {
            JSON.parse(str);
        } catch (e) {
            var message = 'Error while parsing the message payload, please send correct content';
            throw exceptionModule.buildExceptionObject(message, constants.STATUS_CODES.BAD_REQUEST);
        }
        return true;
    }

    var parseContentType = function(contentTypString) {
        var comps = contentTypString.split(';');
        return comps[0];
    };
    /**
     * Allows request data to be sent in either the request body or
     * as url encoded query parameters
     * @param  {Object} req  Request object
     * @return {Object}      An object which contains data from request body and url encoded parameters
     */
    var obtainData = function(req) {
        var data = {};
        var contentType = parseContentType(req.getContentType());
        if (contentType === CONTENT_TYPE_JSON) {
            try {
                data = req.getContent();
            } catch (e) {
                log.error('Unable to obtain content from request', e);
            }
        }
        var params = req.getAllParameters('UTF-8');
        //Mix the content with request parameters
        for (var key in params) {
            data[key] = params[key];
        }
        return data;
    };
    api.state = function(req, res, session, options) {
        if (req.getMethod() !== 'GET') {
            return errorMsg(msg(405, 'State must be retrieved using a GET'));
        }
        validateOptions(options);
        var result;
        try {
            result = lifecycleAPI.getState(options, req, res, session);
        } catch (e) {
            if (e == "Unauthorized Action - does not have permissions to view lifecycle state") {
                var errorResponse = msg(401, 'User does not have permission to view lifecycle state', e);
                errorResponse.errorContent = {};

                errorResponse.errorContent.message = 'User does not have permission to view lifecycle state';
                errorResponse.errorContent.exception = e;

                return errorMsg(errorResponse);
            } else {
                throw e;
            }
        }
        return successMsg(msg(200, 'Asset state information returned', result));
    };
    api.changeState = function(req, res, session, options) {
        var newState = null;
        var result = {};
        var data;
        var succcess;
        if (req.getMethod() !== 'POST') {
            return errorMsg(msg(405, 'State must be changed by a POST'));
        }
        data = obtainData(req);
        if (!data.nextState) {
            log.error('State change requires a nextState to be provided either as a query string or in the body of the request');
            return errorMsg(msg(400, 'State change requires a nextState to be provided either as a query string or in the body of the request'));
        }
        options.nextState = data.nextState;
        options.comment = data.comment;
        //Call the state change api

        try {
            success = lifecycleAPI.changeState(options, req, res, session);
        } catch (e) {
            throw e;
        }
        if (success) {
            //Obtain the next states
            result.newState = data.nextState;
            result.traversableStates = lifecycleAPI.traversableStates(options, req, res, session);
        }
        if (success) {
            return successMsg(msg(200, 'The assets state was changed', result));
        } else {
            return errorMsg(msg(500, 'The asset state was not changed'));
        }
    };
    api.updateCheckList = function(req, res, session, options) {
        var success;
        var body;
        if (!req.getContent() || !req.getContentType() === 'application/json') {
            var message = 'Checklist items must be sent in the body of the request and content type should be set to application/json';
            throw exceptionModule.buildExceptionObject(message, constants.STATUS_CODES.BAD_REQUEST);
        }
        body = req.getContent();
        if((typeof body) == 'string'){
            try {
                body = parse(body);
            } catch (e) {
                var message = 'Error while parsing the message payload, please send correct content';
                throw exceptionModule.buildExceptionObject(message, constants.STATUS_CODES.BAD_REQUEST);
            }
        }
        options.checkItems = body.checklist || [];
        success = lifecycleAPI.checkItems(options, req, res, session);
        if (success) {
            return successMsg(msg(200, 'The checklist was updated successfully'));
        }
        return errorMsg(msg(500, 'The checklist was not updated'));
    };
    api.lifecycleHistory = function(req, res, session, options) {
        var history = lifecycleAPI.getHistory(options, req, res, session);
        //var xmlHistoryContent = new XML(history.content);
        //var historyContent = utils.xml.convertE4XtoJSON(xmlHistoryContent)||{};
        return successMsg(msg(200, 'Lifecycle history retrieved successfully', history.item || []));
    };
    api.addTags = function(req, res, session, options) {
        var success;
        if(req.getMethod() !== 'POST'){
            return errorMsg(msg(405, 'Tags must be added by a POST'));
        }
        try {
            success = tagsAPI.addTags(req, res, session, options);
        } catch (e) {
            log.error(e);
        }
        if (success) {
            return successMsg(msg(200, 'Tags added successfully'));
        }
        return errorMsg(msg(500, 'Tags were not added'));
    };
    api.removeTags = function(req, res, session, options) {
        var success;
        if(req.getMethod() !== 'DELETE'){
            return errorMsg(msg(405, 'Tags must be removed using a DELETE'));
        }
        try {
            success = tagsAPI.removeTags(req, res, session, options);
        } catch (e) {
            log.error(e);
        }
        if (success) {
            return successMsg(msg(200, 'Tags removed successfully'));
        }
        return errorMsg(msg(500, 'Tags were not removed'));
    };
    api.tags = function(req, res, session, options) {
        var tags = [];
        var success;
        if(req.getMethod() !== 'GET'){
            return errorMsg(msg(405, 'Tags must be retrieved using a GET'));
        }
        try {
            tags = tagsAPI.tags(req,res,session,options);
            success = true;
        } catch(e){
            log.error(e);
        }
        if (success) {
            return successMsg(msg(200, 'Tags of the asset retrieved successfully', tags));
        }
        return errorMsg(msg(500, 'Tags were not retrieved'));
    };
    /**
     * api to create  a new version of the given asset
     * @param  options Object containing asset id, type, new version
     * @param  req     jaggery request
     * @param  res     jaggery response
     * @param  session  sessionId
     * @return The created asset or null if failed to create the asset
     */
    api.createVersion = function(req, res, session, options) {
        var asset;
        var createdAsset;
        var attributes;
        var assetModule = rxtModule.asset;
        var am = assetModule.createUserAssetManager(session, options.type);
        if(req.getMethod() !== 'POST'){
            return errorMsg(msg(405, 'Create version should be done using a POST'));
        }
        var content = req.getContent();
        validatePayload(content);
        var data = parse(content);
        var existingAsset = assetAPI.get(options,req,res,session);
        var newVersion = data.attributes.overview_version;
        var resources = am.getAssetGroup(existingAsset);
        for (var index in resources) {
            if (resources.hasOwnProperty(index)) {
                var resource = resources[index];
                if(resource.version === newVersion){
                    return errorMsg(msg(409, 'Conflict in versions: '+ newVersion + ' already exist!')); /* REST POST request "409 Conflict" since the resource pointed exists.*/
                }
            }
        }
        try {
            asset = am.createVersion(options, data.attributes);
            if(asset){
                 tenantId = es.current(session).tenantId;
                var registry = es.systemRegistry(tenantId);

                if(registry.registry.resourceExists('/_system/governance/store/asset_resources/'+ options.type + '/' + options.id)){
                    registry.registry.copy('/_system/governance/store/asset_resources/'+ options.type + '/' + options.id,'/_system/governance/store/asset_resources/'+ options.type + '/' + asset);
                }
                return successMsg(msg(200, 'New version created successfully.', asset));
            }
            return errorMsg(msg(500, 'New version of asset of id:'+ options.id + ' could not be created.'));

        } catch (e) {
            log.error('Asset of type: ' + options.type + ' was not created due to ' ,e);
            return errorMsg(msg(500, 'New version of asset of id :'+ options.id + ' could not be created.'));
        }
    };
    api.resolve = function(req, res, session, options) {
        var action = options.action;
        var result = errorMsg(msg(HTTP_ERROR_NOT_IMPLEMENTED, MSG_ERROR_NOT_IMPLEMENTED));
        switch (action) {
            case ACTION_STATE:
                result = api.state(req, res, session, options);
                break;
            case ACTION_CHANGE_STATE:
                result = api.changeState(req, res, session, options);
                break;
            case ACTION_UPDATE_CHECKLIST:
                result = api.updateCheckList(req, res, session, options);
                break;
            case ACTION_LC_HISTORY:
                result = api.lifecycleHistory(req, res, session, options);
                break;
            case ACTION_ADD_TAGS:
                result = api.addTags(req, res, session, options);
                break;
            case ACTION_REMOVE_TAGS:
                result = api.removeTags(req, res, session, options);
                break;
            case ACTION_RETRIEVE_TAGS:
                result = api.tags(req, res, session, options);
                break;
            case ACTION_CREATE_VERSION:
                result = api.createVersion(req, res, session, options);
                break;
            default:
                break;
        }
        return result;
    };
}(api));<|endoftext|>


<commit_before>var EventHandler = function(type)
{
  if(!window.eventHandlers)
  {
    window.eventHandlers = {};
  }
  if(window.eventHandlers[type])
  {
    return;
  }

  window.eventHandlers[type] = {};

  var handler = function(event)
  {

    var ele = event.target, handler = ele.getAttribute('handler'), container = null;
    while( !handler && ( ele = ele.parentElement ) )
    {
      handler = ele.getAttribute('handler');
    }
    if( handler && eventHandlers[type][handler] )
    {
      if( type == 'click' && /toolbar-buttons/.test(ele.parentNode.nodeName) )
      {
        container =
          document.getElementById(ele.parentNode.parentNode.id.replace('toolbar', 'container'));
      }
      eventHandlers[type][handler](event, ele, container);
    }
  }

  this.post = function(handler, event)
  {
    if(eventHandlers[type][handler])
    {
      eventHandlers[type][handler](event);
    }
  }

  document.addEventListener(type, handler, false);
}

new EventHandler('click');
new EventHandler('change');
new EventHandler('input');
new EventHandler('keyup');

/***** click handler *****/

eventHandlers.click['tab'] = function(event, target)
{
  target = target.parentElement;
  var tabs = UIBase.getUIById(target.parentElement.getAttribute('ui-id'));
  var view_id = target.getAttribute('ref-id');
  if( tabs )
  {
    tabs.setActiveTab(view_id);
    messages.post("show-view", {id: view_id});
  }
  else
  {
    opera.postError("tabs is missing in eventHandlers.click['tab'] in ui-actions");
  }
}

eventHandlers.click['close-tab'] = function(event, target)
{
  target = target.parentElement;
  var container = target.parentElement;
  var tabs = UI.prototype.getUIById(target.parentElement.getAttribute('ui-id'));
  tabs.removeTab(target.getAttribute('ref-id'));
}

eventHandlers.click['settings-tabs'] = function(event, target)
{
  var tabs = UIBase.getUIById(target.parentElement.getAttribute('ui-id'));
  windows.showWindow('window-3', 'Settings', templates.settings(tabs), 200, 200, 200, 200);
}

eventHandlers.click['toggle-setting'] = function(event)
{
  var target = event.target;
  var old_setting = target.parentElement.parentElement;
  var view_id = target.getAttribute('view-id');
  var view = views[view_id];
  var setting = document.render(templates.setting( view_id, view.name, !target.hasClass('unfolded') ));
  old_setting.parentElement.replaceChild(setting, old_setting);
}

eventHandlers.click['show-window'] = function(event)
{
  var target = event.target;
  var view_id = target.getAttribute('view-id');
  target.parentNode.parentNode.parentNode.removeChild(target.parentNode.parentNode);
  UIWindowBase.showWindow(view_id);
}

eventHandlers.click['top-settings'] = function(event)
{
  UIWindowBase.showWindow('settings_view');
}

eventHandlers.click['toolbar-switch'] = function(event)
{
  var target = event.target;
  var arr = target.getAttribute('key').split('.');
  var setting = arr[0], key = arr[1];
  var is_active = !( target.getAttribute('is-active') == 'true' && true || false );
  settings[setting].set(key, is_active);
  views.settings_view.syncSetting(setting, key, is_active);
  views[setting].update();
  messages.post("setting-changed", {id: setting, key: key});
  target.setAttribute('is-active', is_active ? 'true' : 'false');

}

/***** change handler *****/

eventHandlers.change['checkbox-setting'] = function(event)
{
  var ele = event.target;
  var view_id = ele.getAttribute('view-id');
  settings[view_id].set(ele.name, ele.checked);
  views[view_id].update();
  var host_view = ele.getAttribute('host-view-id');
  if( host_view )
  {
    views.settings_view.syncSetting(view_id, ele.name, ele.checked);
  }
  messages.post("setting-changed", {id: view_id, key: ele.name});
}

<commit_msg>try to fix  Bug 322448<commit_after>var EventHandler = function(type)
{
  if(!window.eventHandlers)
  {
    window.eventHandlers = {};
  }
  if(window.eventHandlers[type])
  {
    return;
  }

  window.eventHandlers[type] = {};

  var handler = function(event)
  {
    var ele = event.target, handler = ele.getAttribute('handler'), container = null;
    while( !handler && ( ele = ele.parentElement ) )
    {
      handler = ele.getAttribute('handler');
    }
    if( handler && eventHandlers[type][handler] )
    {
      if( type == 'click' && /toolbar-buttons/.test(ele.parentNode.nodeName) )
      {
        container =
          document.getElementById(ele.parentNode.parentNode.id.replace('toolbar', 'container'));
      }
      eventHandlers[type][handler](event, ele, container);
    }
  }

  this.post = function(handler, event)
  {
    if(eventHandlers[type][handler])
    {
      eventHandlers[type][handler](event);
    }
  }

  document.addEventListener(type, handler, false);
}

new EventHandler('click');
new EventHandler('change');
new EventHandler('input');
new EventHandler('keyup');
new EventHandler('mousedown');

/***** click handler *****/

eventHandlers.click['tab'] = function(event, target)
{
  target = target.parentElement;
  var tabs = UIBase.getUIById(target.parentElement.getAttribute('ui-id'));
  var view_id = target.getAttribute('ref-id');
  if( tabs )
  {
    tabs.setActiveTab(view_id);
    messages.post("show-view", {id: view_id});
  }
  else
  {
    opera.postError("tabs is missing in eventHandlers.click['tab'] in ui-actions");
  }
}

eventHandlers.click['close-tab'] = function(event, target)
{
  target = target.parentElement;
  var container = target.parentElement;
  var tabs = UIBase.getUIById(target.parentElement.getAttribute('ui-id'));
  tabs.removeTab(target.getAttribute('ref-id'));
}

eventHandlers.click['settings-tabs'] = function(event, target)
{
  var tabs = UIBase.getUIById(target.parentElement.getAttribute('ui-id'));
  windows.showWindow('window-3', 'Settings', templates.settings(tabs), 200, 200, 200, 200);
}

eventHandlers.click['toggle-setting'] = function(event)
{
  var target = event.target;
  var old_setting = target.parentElement.parentElement;
  var view_id = target.getAttribute('view-id');
  var view = views[view_id];
  var setting = document.render(templates.setting( view_id, view.name, !target.hasClass('unfolded') ));
  old_setting.parentElement.replaceChild(setting, old_setting);
}

eventHandlers.click['show-window'] = function(event)
{
  var target = event.target;
  var view_id = target.getAttribute('view-id');
  target.parentNode.parentNode.parentNode.removeChild(target.parentNode.parentNode);
  UIWindowBase.showWindow(view_id);
}

eventHandlers.click['top-settings'] = function(event)
{
  UIWindowBase.showWindow('settings_view');
}

eventHandlers.click['documentation'] = function(event)
{
  views.documentation.setURL( event.target.getAttribute('param'))
  UIWindowBase.showWindow('documentation');
}

eventHandlers.mousedown['toolbar-switch'] = function(event)
{
  var target = event.target;
  var arr = target.getAttribute('key').split('.');
  var setting = arr[0], key = arr[1];
  var is_active = !( target.getAttribute('is-active') == 'true' && true || false );
  settings[setting].set(key, is_active);
  views.settings_view.syncSetting(setting, key, is_active);
  views[setting].update();
  messages.post("setting-changed", {id: setting, key: key});
  target.setAttribute('is-active', is_active ? 'true' : 'false');
}

/***** change handler *****/

eventHandlers.change['checkbox-setting'] = function(event)
{
  var ele = event.target;
  var view_id = ele.getAttribute('view-id');
  settings[view_id].set(ele.name, ele.checked);
  views[view_id].update();
  var host_view = ele.getAttribute('host-view-id');
  if( host_view )
  {
    views.settings_view.syncSetting(view_id, ele.name, ele.checked);
  }
  messages.post("setting-changed", {id: view_id, key: ele.name});
}

<|endoftext|>


<commit_before>import app from 'app';
import _ from 'lodash';
import template from 'text!./edit-modified-organism.directive.html';
import 'views/forms/edit/edit';
import 'services/main';
import '~/views/forms/edit/bch/directives/lmo-construct';
import 'views/forms/edit/document-selector';
import "~/views/forms/view/bch/view-lmo.directive";
import '~/views/forms/directives/traits-selector.directive';
import '~/views/forms/directives/view-terms-hierarchy';

	app.directive("editModifiedOrganism", ["$http", "$controller", "thesaurusService", 'IStorage', '$q', 'realm',
		 function($http, $controller, thesaurusService, storage, $q, realm) {

		return {
			restrict   : "EA",
			template: template,
			replace    : true,
			require    : '?ngModel',
			scope:{
				onPostSubmitFn   : "&onPostSubmit"
			},
			link: function($scope, $element, $attr){
				var oldGenes = [];
				$scope.scientificNameSynonyms = [{}];
				$scope.commonNames = [{}];
				$scope.container        = $attr.container;
    			$scope.isDialog         = $attr.isDialog;
				$scope.type 			= $attr.documentType;
				$controller('editController', {
					$scope: $scope
				});

				_.extend($scope.options, {
					techniqueUsed	: thesaurusService.getDomainTerms('techniqueUsed', 		{other:true, otherType:'lstring', multiple:true}),
					commonUses 		: thesaurusService.getDomainTerms('OrganismCommonUses', {other:true, otherType:'lstring', multiple:true})
				});

				$scope.onContactQuery = function(searchText){

					var queryOptions = {
						realm     : realm.value,
						fieldQueries: ['schema_s:contact AND type_s:person'],
						searchText: searchText
					}

					return $scope.onBuildDocumentSelectorQuery(queryOptions);
				}

				$scope.onRrecipientOrganismsQuery = function(searchText){

					var queryOptions = {
						realm     : realm.value,
						schemas	  : ['organism', 'modifiedOrganism'],
						searchText: searchText
					}
					return $scope.onBuildDocumentSelectorQuery(queryOptions);
				}

				$scope.onBuildQuery = function(searchText, schemasVal){

					var queryOptions = {
						realm     : realm.value,
						schemas	  : [schemasVal],
						searchText: searchText
					}
					return $scope.onBuildDocumentSelectorQuery(queryOptions);
				}
				//==================================
				//
				//==================================
				$scope.getCleanDocument = function(document) {

					document = document || $scope.document;

					if (!document)
						return undefined;

					//temp
					if(document.hasUniqueIdentification==undefined && document.uniqueIdentification)
						document.hasUniqueIdentification = true;

					if((document.traits||[]).length == 0)
						document.traits = undefined;
					if (/^\s*$/g.test(document.notes))
						document.notes = undefined;

					return $scope.sanitizeDocument(document);
				};

				$scope.onModifiedGeneChange = function(genes){
					var geneIdentifiers = _.map(genes||[], 'identifier');
					var newGenes = _.filter(geneIdentifiers, function(identifier){ return !_.includes(oldGenes, identifier) });

					if(newGenes.length){
						updateOldGenes($scope.document);
						$scope.loadingGeneTraits = true;
						var queries = _.map(newGenes, function(identifier){return loadReferenceDocment(identifier).then(function(result){return result.data;})});
						$q.all(queries)
						.then(function(documents){
							var newTraits = _(documents).map('body').map('traits').flatten().compact().flatten().uniq().value();
							if(newTraits.length){

								var newDocumentTraits = angular.copy($scope.document.traits||[]);
								_.forEach(newTraits, function(trait){
									if(trait.customValue || !_.find(newDocumentTraits, trait)){
										newDocumentTraits.push(trait);
									}
								})
								if(newDocumentTraits.length)
									$scope.document.traits = _.union($scope.document.traits, newDocumentTraits);
							}
						})
						.finally(function(){
							$scope.loadingGeneTraits = false;
						})
					}
				}

				$scope.onConstructChange = function(){
					var constructIds = _($scope.document.geneConstructs).flatten().compact().value();

					if(constructIds.length>0 && !$scope.document.genes)
						$scope.document.genes = [];

					_.forEach(constructIds, function(cons){
						if(cons.identifier && !_.find($scope.document.genes, {identifier: cons.identifier}))
							$scope.document.genes.push({ identifier:cons.identifier })
					});

				}

				$scope.lookupDetections = function(){
					var uniqueIdentifier = $scope.document.uniqueIdentification;
					if(!uniqueIdentifier)
						return;

					$scope.lookingupDetections =true

					$http.get('/api/v2020/bch/lmo-detection-methods/'+uniqueIdentifier)
					.then(function(result){
						if(result.data){
							var exists = _.find($scope.document.detectionMethodLinks, {url: decodeURIComponent(result.data.url)})
							if(!exists){
								var newMethods = angular.copy($scope.document.detectionMethodLinks||[]);
								$scope.document.detectionMethodLinks = undefined;
								newMethods.push({
									url:result.data.url,
									name: uniqueIdentifier + ' - EU Reference Laboratory for GM Food and Feed (EURL-GMFF)',
									language: 'lang-en'
								});
								$scope.document.detectionMethodLinks = newMethods;
							}
							//
						}
					})
					.finally(function(){
						$scope.lookingupDetections = false;
					})
				}

				$scope.setDocument({}, true).then(updateOldGenes);

				function updateOldGenes(document){
					oldGenes = _.map(document.genes||[], 'identifier');
				}
				function loadReferenceDocment(identifier){
					return storage.drafts.get(identifier, { info: true })
					.catch(function(e){
						if (e.status == 404)
							return storage.documents.get(identifier, { info: true });
					});
				}
			}
		}

   }]);

<commit_msg>LMO: hide-self in document-selector<commit_after>import app from 'app';
import _ from 'lodash';
import template from 'text!./edit-modified-organism.directive.html';
import 'views/forms/edit/edit';
import 'services/main';
import '~/views/forms/edit/bch/directives/lmo-construct';
import 'views/forms/edit/document-selector';
import "~/views/forms/view/bch/view-lmo.directive";
import '~/views/forms/directives/traits-selector.directive';
import '~/views/forms/directives/view-terms-hierarchy';

	app.directive("editModifiedOrganism", ["$http", "$controller", "thesaurusService", 'IStorage', '$q', 'realm', 'solr',
		 function($http, $controller, thesaurusService, storage, $q, realm, solr) {

		return {
			restrict   : "EA",
			template: template,
			replace    : true,
			require    : '?ngModel',
			scope:{
				onPostSubmitFn   : "&onPostSubmit"
			},
			link: function($scope, $element, $attr){
				var oldGenes = [];
				$scope.scientificNameSynonyms = [{}];
				$scope.commonNames = [{}];
				$scope.container        = $attr.container;
    			$scope.isDialog         = $attr.isDialog;
				$scope.type 			= $attr.documentType;
				$controller('editController', {
					$scope: $scope
				});

				_.extend($scope.options, {
					techniqueUsed	: thesaurusService.getDomainTerms('techniqueUsed', 		{other:true, otherType:'lstring', multiple:true}),
					commonUses 		: thesaurusService.getDomainTerms('OrganismCommonUses', {other:true, otherType:'lstring', multiple:true})
				});

				$scope.onContactQuery = function(searchText){

					var queryOptions = {
						realm     : realm.value,
						fieldQueries: ['schema_s:contact AND type_s:person'],
						searchText: searchText
					}

					return $scope.onBuildDocumentSelectorQuery(queryOptions);
				}

				$scope.onRrecipientOrganismsQuery = function(searchText){

					var queryOptions = {
						realm     : realm.value,
						schemas	  : ['organism', 'modifiedOrganism'],
						searchText: searchText
					}
					if($scope.document?.header.identifier)
                   		 queryOptions.fieldQueries = ["NOT (identifier_s:" + solr.escape($scope.document.header.identifier)+ ")"];
					return $scope.onBuildDocumentSelectorQuery(queryOptions);
				}

				$scope.onBuildQuery = function(searchText, schemasVal){

					var queryOptions = {
						realm     : realm.value,
						schemas	  : [schemasVal],
						searchText: searchText
					}
					if(schemasVal=="modifiedOrganism" && $scope.document?.header.identifier){
                        queryOptions.fieldQueries = ["NOT (identifier_s:" + solr.escape($scope.document.header.identifier)+ ")"];
                    }
					return $scope.onBuildDocumentSelectorQuery(queryOptions);
				}
				//==================================
				//
				//==================================
				$scope.getCleanDocument = function(document) {

					document = document || $scope.document;

					if (!document)
						return undefined;

					//temp
					if(document.hasUniqueIdentification==undefined && document.uniqueIdentification)
						document.hasUniqueIdentification = true;

					if((document.traits||[]).length == 0)
						document.traits = undefined;
					if (/^\s*$/g.test(document.notes))
						document.notes = undefined;

					return $scope.sanitizeDocument(document);
				};

				$scope.onModifiedGeneChange = function(genes){
					var geneIdentifiers = _.map(genes||[], 'identifier');
					var newGenes = _.filter(geneIdentifiers, function(identifier){ return !_.includes(oldGenes, identifier) });

					if(newGenes.length){
						updateOldGenes($scope.document);
						$scope.loadingGeneTraits = true;
						var queries = _.map(newGenes, function(identifier){return loadReferenceDocment(identifier).then(function(result){return result.data;})});
						$q.all(queries)
						.then(function(documents){
							var newTraits = _(documents).map('body').map('traits').flatten().compact().flatten().uniq().value();
							if(newTraits.length){

								var newDocumentTraits = angular.copy($scope.document.traits||[]);
								_.forEach(newTraits, function(trait){
									if(trait.customValue || !_.find(newDocumentTraits, trait)){
										newDocumentTraits.push(trait);
									}
								})
								if(newDocumentTraits.length)
									$scope.document.traits = _.union($scope.document.traits, newDocumentTraits);
							}
						})
						.finally(function(){
							$scope.loadingGeneTraits = false;
						})
					}
				}

				$scope.onConstructChange = function(){
					var constructIds = _($scope.document.geneConstructs).flatten().compact().value();

					if(constructIds.length>0 && !$scope.document.genes)
						$scope.document.genes = [];

					_.forEach(constructIds, function(cons){
						if(cons.identifier && !_.find($scope.document.genes, {identifier: cons.identifier}))
							$scope.document.genes.push({ identifier:cons.identifier })
					});

				}

				$scope.lookupDetections = function(){
					var uniqueIdentifier = $scope.document.uniqueIdentification;
					if(!uniqueIdentifier)
						return;

					$scope.lookingupDetections =true

					$http.get('/api/v2020/bch/lmo-detection-methods/'+uniqueIdentifier)
					.then(function(result){
						if(result.data){
							var exists = _.find($scope.document.detectionMethodLinks, {url: decodeURIComponent(result.data.url)})
							if(!exists){
								var newMethods = angular.copy($scope.document.detectionMethodLinks||[]);
								$scope.document.detectionMethodLinks = undefined;
								newMethods.push({
									url:result.data.url,
									name: uniqueIdentifier + ' - EU Reference Laboratory for GM Food and Feed (EURL-GMFF)',
									language: 'lang-en'
								});
								$scope.document.detectionMethodLinks = newMethods;
							}
							//
						}
					})
					.finally(function(){
						$scope.lookingupDetections = false;
					})
				}

				$scope.setDocument({}, true).then(updateOldGenes);

				function updateOldGenes(document){
					oldGenes = _.map(document.genes||[], 'identifier');
				}
				function loadReferenceDocment(identifier){
					return storage.drafts.get(identifier, { info: true })
					.catch(function(e){
						if (e.status == 404)
							return storage.documents.get(identifier, { info: true });
					});
				}
			}
		}

   }]);

<|endoftext|>


<commit_before>/*jslint browser: true, nomen: true */

(function (flow, $, _, Backbone, Blob, d3, FileReader, girderUpload, URL) {
    "use strict";

    // The view for managing data saving and downloading
    flow.DatasetManagementView = Backbone.View.extend({
        saveFormats: {
            table: ['csv', 'rows.json'],
            tree: ['nested.json', 'nexus', 'newick'],
            image: ['png'],
            r: ['serialized']
        },

        extensions: {
            "table:csv": "csv",
            "table:rows.json": "rows-json",
            "tree:nested.json": "nested-json",
            "tree:nexus": "nex",
            "tree:newick": "phy",
            "image:png": "png",
            "r:serialized": "rds"
        },

        events: {
            'change .datasets': 'updateDataset',

            'click .dataset-save': function () {
                var name = this.$('.dataset-name').val(),
                    format = this.$('.dataset-format-select').val(),
                    dataset = this.datasets.get(this.$('.datasets').val());
                flow.retrieveDatasetAsFormat(dataset, dataset.get('type'), format, false, _.bind(function (error, converted) {
                    var blob = new Blob([converted.get('data')]),
                        extension = this.extensions[dataset.get('type') + ":" + format],
                        parts = name.split('.'),
                        nameWithExtension = parts[parts.length - 1] === extension ? name : name + '.' + extension;
                    girderUpload(blob, nameWithExtension, flow.saveLocation.get('dataFolder'));
                }, this));
            },

            'click .dataset-download': function () {
                var name = this.$('.dataset-name').val(),
                    format = this.$('.dataset-format-select').val(),
                    dataset = this.datasets.get(this.$('.datasets').val());
                flow.retrieveDatasetAsFormat(dataset, dataset.get('type'), format, false, _.bind(function (error, converted) {
                    var blob = new Blob([converted.get('data')]),
                        extension = this.extensions[dataset.get('type') + ":" + format],
                        parts = name.split('.'),
                        nameWithExtension = parts[parts.length - 1] === extension ? name : name + '.' + extension,
                        anchor = $('');
                    anchor[0].click();
                }, this));
            },

            'change #g-files': function () {
                var files = $('#g-files')[0].files;
                _.each(files, function (file) {
                    this.upload(file);
                }, this);
            },

            'click #upload': function () {
                $('#g-files').click();
            },

            'dragenter #upload': function (e) {
                e.stopPropagation();
                e.preventDefault();
                e.originalEvent.dataTransfer.dropEffect = 'copy';
                d3.select('#upload')
                    .classed('btn-success', true)
                    .classed('btn-primary', false)
                    .html(' Drop files here');
            },

            'dragleave #upload': function (e) {
                e.stopPropagation();
                e.preventDefault();
                d3.select('#upload')
                    .classed('btn-success', false)
                    .classed('btn-primary', true)
                    .html(' Browse or drop files');
            },

            'dragover #upload': function (e) {
                e.preventDefault();
            },

            'drop #upload': function (e) {
                var files = e.originalEvent.dataTransfer.files;
                e.stopPropagation();
                e.preventDefault();
                d3.select('#upload')
                    .classed('btn-success', false)
                    .classed('btn-primary', true)
                    .html(' Browse or drop files');
                _.each(files, function (file) {
                    this.upload(file);
                }, this);
            }
        },

        initialize: function (settings) {
            this.datasets = settings.datasets;
            this.datasetsView = new flow.ItemsView({el: this.$('.datasets'), itemView: flow.ItemOptionView, collection: this.datasets});
            this.datasetsView.render();
            flow.events.on('flow:change-save-location', this.saveLocationChange, this);
            this.saveLocationChange();

            // Once the first dataset is added, make it the active dataset
            this.datasets.on('add', _.bind(function () {
                if (!this.dataset) {
                    this.updateDataset();
                }
            }, this));
        },

        upload: function (file) {
            var reader = new FileReader();

            reader.onload = _.bind(function (e) {
                var dataset = {
                        name: file.name,
                        data: e.target.result
                    },
                    extension = file.name.split('.');

                extension = extension[extension.length - 1];
                _.extend(dataset, flow.extensionToType[extension]);
                dataset = new Backbone.Model(dataset);

                this.datasets.add(dataset);
            }, this);

            reader.readAsText(file);
        },

        updateDataset: function () {
            var options, valid;
            this.dataset = this.datasets.get(this.$('.datasets').val());

            // If we don't know the format, don't let them download it
            valid = this.dataset.get('type') !== undefined && this.dataset.get('format') !== undefined;
            this.$('.dataset-save-form').toggleClass('hidden', !valid);

            if (valid) {
                this.$('.dataset-name').val(this.dataset.get('name'));
                options = d3.select('.dataset-format-select').selectAll('option')
                    .data(this.saveFormats[this.dataset.get('type')], function (d) { return d; });
                options.enter().append('option')
                    .text(function (d) { return d; })
                    .attr('value', function (d) { return d; });
                options.exit().remove();
            }
        },

        saveLocationChange: function () {
            this.$('.dataset-save').toggleClass('hidden', flow.saveLocation === null);
        }
    });

}(window.flow, window.$, window._, window.Backbone, window.Blob, window.d3, window.FileReader, window.girderUpload, window.URL));
<commit_msg>Update collection on saved datasets properly<commit_after>/*jslint browser: true, nomen: true */

(function (flow, $, _, Backbone, Blob, d3, FileReader, girderUpload, URL) {
    "use strict";

    // The view for managing data saving and downloading
    flow.DatasetManagementView = Backbone.View.extend({
        saveFormats: {
            table: ['csv', 'rows.json'],
            tree: ['nested.json', 'nexus', 'newick'],
            image: ['png'],
            r: ['serialized']
        },

        extensions: {
            "table:csv": "csv",
            "table:rows.json": "rows-json",
            "tree:nested.json": "nested-json",
            "tree:nexus": "nex",
            "tree:newick": "phy",
            "image:png": "png",
            "r:serialized": "rds"
        },

        events: {
            'change .datasets': 'updateDataset',

            'click .dataset-save': function () {
                var name = this.$('.dataset-name').val(),
                    format = this.$('.dataset-format-select').val(),
                    dataset = this.datasets.get(this.$('.datasets').val());
                flow.retrieveDatasetAsFormat(dataset, dataset.get('type'), format, false, _.bind(function (error, converted) {
                    var blob = new Blob([converted.get('data')]),
                        extension = this.extensions[dataset.get('type') + ":" + format],
                        parts = name.split('.'),
                        nameWithExtension = parts[parts.length - 1] === extension ? name : name + '.' + extension;
                    girderUpload(blob, nameWithExtension, flow.saveLocation.get('dataFolder'));
                    dataset.set({collection: flow.saveLocation});
                }, this));
            },

            'click .dataset-download': function () {
                var name = this.$('.dataset-name').val(),
                    format = this.$('.dataset-format-select').val(),
                    dataset = this.datasets.get(this.$('.datasets').val());
                flow.retrieveDatasetAsFormat(dataset, dataset.get('type'), format, false, _.bind(function (error, converted) {
                    var blob = new Blob([converted.get('data')]),
                        extension = this.extensions[dataset.get('type') + ":" + format],
                        parts = name.split('.'),
                        nameWithExtension = parts[parts.length - 1] === extension ? name : name + '.' + extension,
                        anchor = $('');
                    anchor[0].click();
                }, this));
            },

            'change #g-files': function () {
                var files = $('#g-files')[0].files;
                _.each(files, function (file) {
                    this.upload(file);
                }, this);
            },

            'click #upload': function () {
                $('#g-files').click();
            },

            'dragenter #upload': function (e) {
                e.stopPropagation();
                e.preventDefault();
                e.originalEvent.dataTransfer.dropEffect = 'copy';
                d3.select('#upload')
                    .classed('btn-success', true)
                    .classed('btn-primary', false)
                    .html(' Drop files here');
            },

            'dragleave #upload': function (e) {
                e.stopPropagation();
                e.preventDefault();
                d3.select('#upload')
                    .classed('btn-success', false)
                    .classed('btn-primary', true)
                    .html(' Browse or drop files');
            },

            'dragover #upload': function (e) {
                e.preventDefault();
            },

            'drop #upload': function (e) {
                var files = e.originalEvent.dataTransfer.files;
                e.stopPropagation();
                e.preventDefault();
                d3.select('#upload')
                    .classed('btn-success', false)
                    .classed('btn-primary', true)
                    .html(' Browse or drop files');
                _.each(files, function (file) {
                    this.upload(file);
                }, this);
            }
        },

        initialize: function (settings) {
            this.datasets = settings.datasets;
            this.datasetsView = new flow.ItemsView({el: this.$('.datasets'), itemView: flow.ItemOptionView, collection: this.datasets});
            this.datasetsView.render();
            flow.events.on('flow:change-save-location', this.saveLocationChange, this);
            this.saveLocationChange();

            // Once the first dataset is added, make it the active dataset
            this.datasets.on('add', _.bind(function () {
                if (!this.dataset) {
                    this.updateDataset();
                }
            }, this));
        },

        upload: function (file) {
            var reader = new FileReader();

            reader.onload = _.bind(function (e) {
                var dataset = {
                        name: file.name,
                        data: e.target.result
                    },
                    extension = file.name.split('.');

                extension = extension[extension.length - 1];
                _.extend(dataset, flow.extensionToType[extension]);
                dataset = new Backbone.Model(dataset);

                this.datasets.off('add', null, 'set-collection').add(dataset);
            }, this);

            reader.readAsText(file);
        },

        updateDataset: function () {
            var options, valid;
            this.dataset = this.datasets.get(this.$('.datasets').val());

            // If we don't know the format, don't let them download it
            valid = this.dataset.get('type') !== undefined && this.dataset.get('format') !== undefined;
            this.$('.dataset-save-form').toggleClass('hidden', !valid);

            if (valid) {
                this.$('.dataset-name').val(this.dataset.get('name'));
                options = d3.select('.dataset-format-select').selectAll('option')
                    .data(this.saveFormats[this.dataset.get('type')], function (d) { return d; });
                options.enter().append('option')
                    .text(function (d) { return d; })
                    .attr('value', function (d) { return d; });
                options.exit().remove();
            }
        },

        saveLocationChange: function () {
            this.$('.dataset-save').toggleClass('hidden', flow.saveLocation === null);
        }
    });

}(window.flow, window.$, window._, window.Backbone, window.Blob, window.d3, window.FileReader, window.girderUpload, window.URL));
<|endoftext|>


<commit_before>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow
 */

import type {Dispatcher as DispatcherType} from 'react-reconciler/src/ReactInternalTypes';
import type {Request} from './ReactFlightServer';
import type {ReactServerContext} from 'shared/ReactTypes';
import {REACT_SERVER_CONTEXT_TYPE} from 'shared/ReactSymbols';
import {readContext as readContextImpl} from './ReactFlightNewContext';

let currentRequest = null;

export function prepareToUseHooksForRequest(request: Request) {
  currentRequest = request;
}

export function resetHooksForRequest() {
  currentRequest = null;
}

function readContext<T>(context: ReactServerContext<T>): T {
  if (__DEV__) {
    if (context.$$typeof !== REACT_SERVER_CONTEXT_TYPE) {
      console.error('Only ServerContext is supported in Flight');
    }
    if (currentCache === null) {
      console.error(
        'Context can only be read while React is rendering. ' +
          'In classes, you can read it in the render method or getDerivedStateFromProps. ' +
          'In function components, you can read it directly in the function body, but not ' +
          'inside Hooks like useReducer() or useMemo().',
      );
    }
  }
  return readContextImpl(context);
}

export const Dispatcher: DispatcherType = {
  useMemo<T>(nextCreate: () => T): T {
    return nextCreate();
  },
  useCallback<T>(callback: T): T {
    return callback;
  },
  useDebugValue(): void {},
  useDeferredValue: (unsupportedHook: any),
  useTransition: (unsupportedHook: any),
  getCacheForType<T>(resourceType: () => T): T {
    if (!currentCache) {
      throw new Error('Reading the cache is only supported while rendering.');
    }

    let entry: T | void = (currentCache.get(resourceType): any);
    if (entry === undefined) {
      entry = resourceType();
      // TODO: Warn if undefined?
      currentCache.set(resourceType, entry);
    }
    return entry;
  },
  readContext,
  useContext: readContext,
  useReducer: (unsupportedHook: any),
  useRef: (unsupportedHook: any),
  useState: (unsupportedHook: any),
  useInsertionEffect: (unsupportedHook: any),
  useLayoutEffect: (unsupportedHook: any),
  useImperativeHandle: (unsupportedHook: any),
  useEffect: (unsupportedHook: any),
  useId,
  useMutableSource: (unsupportedHook: any),
  useSyncExternalStore: (unsupportedHook: any),
  useCacheRefresh(): <T>(?() => T, ?T) => void {
    return unsupportedRefresh;
  },
  useMemoCache(size: number): Array<any> {
    return new Array(size);
  },
};

function unsupportedHook(): void {
  throw new Error('This Hook is not supported in Server Components.');
}

function unsupportedRefresh(): void {
  if (!currentCache) {
    throw new Error(
      'Refreshing the cache is not supported in Server Components.',
    );
  }
}

let currentCache: Map<Function, mixed> | null = null;

export function setCurrentCache(cache: Map<Function, mixed> | null) {
  currentCache = cache;
  return currentCache;
}

export function getCurrentCache() {
  return currentCache;
}

function useId(): string {
  if (currentRequest === null) {
    throw new Error('useId can only be used while React is rendering');
  }
  const id = currentRequest.identifierCount++;
  // use 'S' for Flight components to distinguish from 'R' and 'r' in Fizz/Client
  return ':' + currentRequest.identifierPrefix + 'S' + id.toString(32) + ':';
}
<commit_msg>Don't use the Flight terminology in public error messages (#25166)<commit_after>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow
 */

import type {Dispatcher as DispatcherType} from 'react-reconciler/src/ReactInternalTypes';
import type {Request} from './ReactFlightServer';
import type {ReactServerContext} from 'shared/ReactTypes';
import {REACT_SERVER_CONTEXT_TYPE} from 'shared/ReactSymbols';
import {readContext as readContextImpl} from './ReactFlightNewContext';

let currentRequest = null;

export function prepareToUseHooksForRequest(request: Request) {
  currentRequest = request;
}

export function resetHooksForRequest() {
  currentRequest = null;
}

function readContext<T>(context: ReactServerContext<T>): T {
  if (__DEV__) {
    if (context.$$typeof !== REACT_SERVER_CONTEXT_TYPE) {
      console.error(
        'Only createServerContext is supported in Server Components.',
      );
    }
    if (currentCache === null) {
      console.error(
        'Context can only be read while React is rendering. ' +
          'In classes, you can read it in the render method or getDerivedStateFromProps. ' +
          'In function components, you can read it directly in the function body, but not ' +
          'inside Hooks like useReducer() or useMemo().',
      );
    }
  }
  return readContextImpl(context);
}

export const Dispatcher: DispatcherType = {
  useMemo<T>(nextCreate: () => T): T {
    return nextCreate();
  },
  useCallback<T>(callback: T): T {
    return callback;
  },
  useDebugValue(): void {},
  useDeferredValue: (unsupportedHook: any),
  useTransition: (unsupportedHook: any),
  getCacheForType<T>(resourceType: () => T): T {
    if (!currentCache) {
      throw new Error('Reading the cache is only supported while rendering.');
    }

    let entry: T | void = (currentCache.get(resourceType): any);
    if (entry === undefined) {
      entry = resourceType();
      // TODO: Warn if undefined?
      currentCache.set(resourceType, entry);
    }
    return entry;
  },
  readContext,
  useContext: readContext,
  useReducer: (unsupportedHook: any),
  useRef: (unsupportedHook: any),
  useState: (unsupportedHook: any),
  useInsertionEffect: (unsupportedHook: any),
  useLayoutEffect: (unsupportedHook: any),
  useImperativeHandle: (unsupportedHook: any),
  useEffect: (unsupportedHook: any),
  useId,
  useMutableSource: (unsupportedHook: any),
  useSyncExternalStore: (unsupportedHook: any),
  useCacheRefresh(): <T>(?() => T, ?T) => void {
    return unsupportedRefresh;
  },
  useMemoCache(size: number): Array<any> {
    return new Array(size);
  },
};

function unsupportedHook(): void {
  throw new Error('This Hook is not supported in Server Components.');
}

function unsupportedRefresh(): void {
  if (!currentCache) {
    throw new Error(
      'Refreshing the cache is not supported in Server Components.',
    );
  }
}

let currentCache: Map<Function, mixed> | null = null;

export function setCurrentCache(cache: Map<Function, mixed> | null) {
  currentCache = cache;
  return currentCache;
}

export function getCurrentCache() {
  return currentCache;
}

function useId(): string {
  if (currentRequest === null) {
    throw new Error('useId can only be used while React is rendering');
  }
  const id = currentRequest.identifierCount++;
  // use 'S' for Flight components to distinguish from 'R' and 'r' in Fizz/Client
  return ':' + currentRequest.identifierPrefix + 'S' + id.toString(32) + ':';
}
<|endoftext|>


<commit_before>var AsyncVDOMBuilder = require('../runtime/vdom/AsyncVDOMBuilder');
var createElement = require('marko-vdom').createElement;
var expect = require('chai').expect;

it('sync', function() {
    var out = new AsyncVDOMBuilder();
    out.element('div', {}, 0);
    var tree = out.getOutput();
    expect(tree.childNodes.length).to.equal(1);
});

it('end, then listen for finish', function(done) {
    var out = new AsyncVDOMBuilder();
    out.element('div', {}, 0);
    out.end();
    out.on('finish', function(tree) {
        expect(tree.childNodes.length).to.equal(1);
        done();
    });
});

it('async', function(done) {
    var out = new AsyncVDOMBuilder();
    out.element('div', {}, 0);
    var asyncOut = out.beginAsync();

    setTimeout(function() {
        asyncOut.element('span', {}, 0);
        asyncOut.end();
    }, 10);

    out.element('section', {}, 0);

    out.end();
    out.on('finish', function(tree) {
        expect(tree.childNodes.length).to.equal(3);
        expect(tree.firstChild.nodeName).to.equal('div');
        expect(tree.firstChild.nextSibling.nodeName).to.equal('span');
        expect(tree.firstChild.nextSibling.nextSibling.nodeName).to.equal('section');
        done();
    });
});

it('async flush', function(done) {
    var out = new AsyncVDOMBuilder();
    out.on('update', function(tree) {
        expect(tree.childNodes.length).to.equal(1);
    });
    out.once('finish', function(tree) {
        expect(tree.childNodes.length).to.equal(2);
        done();
    });

    out.element('div', {}, 0);
    out.flush();

    var asyncOut = out.beginAsync();

    setTimeout(function() {
        asyncOut.element('span', {}, 0);
        asyncOut.end();
    }, 10);

    out.end();
});

it('for loop', function(done) {
    var out = new AsyncVDOMBuilder();
    out.once('finish', function(tree) {
        var header = tree.childNodes[0];
        var list = tree.childNodes[1];
        var paragraph = tree.childNodes[2];
        expect(header.nodeName).to.equal('h1');
        expect(list.nodeName).to.equal('ul');
        expect(list.childNodes.length).to.equal(10);
        expect(paragraph.nodeName).to.equal('p');
        done();
    });

    out.element('h1', {}, 0);

    out.beginElement('ul', {});

    for(var i = 0; i < 10; i++) {
        out.element('li', {}, 1).t(i);
    }

    out.endElement();

    out.element('p', {}, 0);

    out.end();
});

it('staticNode, text, comment', function(done) {
    var staticNode = createElement('div', {}, 0, 'f891ea3');
    var out = new AsyncVDOMBuilder();

    out.node(staticNode);
    out.text('Hello World');
    out.comment('TODO: make this work');
    out.end();

    out.once('finish', function(tree) {
        expect(tree.childNodes[0].nodeName).to.equal('div');
        expect(tree.childNodes[1].nodeValue).to.equal('Hello World');
        expect(tree.childNodes[2].nodeValue).to.equal('TODO: make this work');
        done();
    });
});

it('should handle timeouts correctly');

it('should handle sync errors correctly');

it('should handle timeout errors correctly');

it('should avoid writes after end');

it('globals');<commit_msg>Fixed reference to marko-vdom<commit_after>var AsyncVDOMBuilder = require('../runtime/vdom/AsyncVDOMBuilder');
var HTMLElement = require('../runtime/vdom/HTMLElement');
var expect = require('chai').expect;

it('sync', function() {
    var out = new AsyncVDOMBuilder();
    out.element('div', {}, 0);
    var tree = out.getOutput();
    expect(tree.childNodes.length).to.equal(1);
});

it('end, then listen for finish', function(done) {
    var out = new AsyncVDOMBuilder();
    out.element('div', {}, 0);
    out.end();
    out.on('finish', function(tree) {
        expect(tree.childNodes.length).to.equal(1);
        done();
    });
});

it('async', function(done) {
    var out = new AsyncVDOMBuilder();
    out.element('div', {}, 0);
    var asyncOut = out.beginAsync();

    setTimeout(function() {
        asyncOut.element('span', {}, 0);
        asyncOut.end();
    }, 10);

    out.element('section', {}, 0);

    out.end();
    out.on('finish', function(tree) {
        expect(tree.childNodes.length).to.equal(3);
        expect(tree.firstChild.nodeName).to.equal('div');
        expect(tree.firstChild.nextSibling.nodeName).to.equal('span');
        expect(tree.firstChild.nextSibling.nextSibling.nodeName).to.equal('section');
        done();
    });
});

it('async flush', function(done) {
    var out = new AsyncVDOMBuilder();
    out.on('update', function(tree) {
        expect(tree.childNodes.length).to.equal(1);
    });
    out.once('finish', function(tree) {
        expect(tree.childNodes.length).to.equal(2);
        done();
    });

    out.element('div', {}, 0);
    out.flush();

    var asyncOut = out.beginAsync();

    setTimeout(function() {
        asyncOut.element('span', {}, 0);
        asyncOut.end();
    }, 10);

    out.end();
});

it('for loop', function(done) {
    var out = new AsyncVDOMBuilder();
    out.once('finish', function(tree) {
        var header = tree.childNodes[0];
        var list = tree.childNodes[1];
        var paragraph = tree.childNodes[2];
        expect(header.nodeName).to.equal('h1');
        expect(list.nodeName).to.equal('ul');
        expect(list.childNodes.length).to.equal(10);
        expect(paragraph.nodeName).to.equal('p');
        done();
    });

    out.element('h1', {}, 0);

    out.beginElement('ul', {});

    for(var i = 0; i < 10; i++) {
        out.element('li', {}, 1).t(i);
    }

    out.endElement();

    out.element('p', {}, 0);

    out.end();
});

it('staticNode, text, comment', function(done) {
    var staticNode = new HTMLElement('div', {}, 0, 'f891ea3');
    var out = new AsyncVDOMBuilder();

    out.node(staticNode);
    out.text('Hello World');
    out.comment('TODO: make this work');
    out.end();

    out.once('finish', function(tree) {
        expect(tree.childNodes[0].nodeName).to.equal('div');
        expect(tree.childNodes[1].nodeValue).to.equal('Hello World');
        expect(tree.childNodes[2].nodeValue).to.equal('TODO: make this work');
        done();
    });
});

// it('should handle timeouts correctly');
//
// it('should handle sync errors correctly');
//
// it('should handle timeout errors correctly');
//
// it('should avoid writes after end');
//
// it('globals');<|endoftext|>


<commit_before>var express = require('express'),
	bodyParser = require('body-parser'),
    authenticate = require('azure-mobile-apps/src/express/middleware/authenticate'),
    authorize = require('azure-mobile-apps/src/express/middleware/authorize');

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

module.exports = function (configuration) {
    var router = express.Router();

	var completeError = function(err, res) {
	    if (err) {
	        console.error(err);
	        if (res) res.sendStatus(500);
	    }
	};

    router.get('/', (req, res, next) => {
		console.log('in GET /tertulias');
		res.send( '' );
		// res.send( '' );
		// res.send( '' );
		res.send( '' );
		res.send( '
Tertulias
' );
		res.send( '
Tertulias
' );
		res.send( '' );
		res.send( '' );
    	next();
    });

    return router;
};
<commit_msg>wip save<commit_after>var express = require('express'),
	bodyParser = require('body-parser'),
    authenticate = require('azure-mobile-apps/src/express/middleware/authenticate'),
    authorize = require('azure-mobile-apps/src/express/middleware/authorize');

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

module.exports = function (configuration) {
    var router = express.Router();

	var completeError = function(err, res) {
	    if (err) {
	        console.error(err);
	        if (res) res.sendStatus(500);
	    }
	};

    router.get('/', (req, res, next) => {
		console.log('in GET /tertulias');
		// res.send( '' );
		// res.send( '' );
		// res.send( '' );
		// res.send( '' );
		res.send( '
Tertulias
' );
		res.send( '
Tertulias
' );
		// res.send( '' );
		// res.send( '' );
    	next();
    });

    return router;
};
<|endoftext|>


<commit_before>var expect = require('chai').expect;
var binarySearch = require('./binary-search');

describe("binary-search", function () {
    it("should return -1 given an empty array", function () {
        expect(binarySearch([], 0)).to.equal(-1);
    });
    it("should return 0 if the array length is 1 and the search key matches", function () {
        expect(binarySearch([1], 1)).to.equal(0);
    });
    it("should return -1 if the array length is 1 and the search key doesn't match", function () {
        expect(binarySearch([2], 1)).to.equal(-1);
    });
    it("should return 0 when looking for 10 in the array [10, 20, 30, 40]", function () {
        expect(binarySearch([10, 20, 30, 40], 10)).to.equal(0);
    });
    it("should return 2 when looking for 30 in the array [10, 20, 30, 40]", function () {
        expect(binarySearch([10, 20, 30, 40], 30)).to.equal(2);
    });
});<commit_msg>New test detected an issue when the length of the array is an odd number (probably related to rounding in the integer division)<commit_after>var expect = require('chai').expect;
var binarySearch = require('./binary-search');

describe("binary-search", function () {
    it("should return -1 given an empty array", function () {
        expect(binarySearch([], 0)).to.equal(-1);
    });
    it("should return 0 if the array length is 1 and the search key matches", function () {
        expect(binarySearch([1], 1)).to.equal(0);
    });
    it("should return -1 if the array length is 1 and the search key doesn't match", function () {
        expect(binarySearch([2], 1)).to.equal(-1);
    });
    it("should return 0 when looking for 10 in the array [10, 20, 30, 40]", function () {
        expect(binarySearch([10, 20, 30, 40], 10)).to.equal(0);
    });
    it("should return 2 when looking for 30 in the array [10, 20, 30, 40]", function () {
        expect(binarySearch([10, 20, 30, 40], 30)).to.equal(2);
    });
    it("should return 2 when looking for 30 in the array [10, 20, 30, 40, 50]", function () {
        expect(binarySearch([10, 20, 30, 40, 50], 30)).to.equal(2);
    });
});<|endoftext|>


<commit_before>// TODO: switch to requireJS or AMD modules
// TODO: convert to backbone?

$(function(){
	mf.init()
	mf.load()
})

var mf = {}

mf.init = function() {
	// put in constructor
	mf.nav.skip    = new mf.controllers.button('#skip')
	mf.nav.discard = new mf.controllers.button('#discard')
	mf.nav.publish = new mf.controllers.button('#publish')
	mf.nav.inspect = new mf.controllers.button('#inspect')
	mf.nav.undo    = new mf.controllers.button('#undo')

	mf.nav.skip.bind('right').bind('j').bind('s')
	mf.nav.discard.bind('x').bind('d').bind('space')
	mf.nav.publish.bind('w').bind('p')
	mf.nav.inspect.bind('i')
	mf.nav.undo.bind('u').bind('ctrl+z')
	mf.nav.undo.disable()

	mf.display = new mf.controllers.display('article')
	mf.display.wait()

	mf.pending = new mf.controllers.counter('#pending')
	// queue refill should load article
	mf.pending.change(function(from, to){
		if (from == 0 && to > 0)
			mf.load()

		document.title =  '('+to+') Megafilter'
		console.log('change to',to,'from',from)
	})

	mf.nav.skip.action(mf.skip)
	mf.nav.discard.action(mf.discard)
	mf.nav.publish.action(mf.publish)
	mf.nav.inspect.action(mf.inspect)
	//mf.nav.undo.action(mf.undo)

	setInterval(mf.check_pending,5000)
}

// render the next article from cache and begin to use the
mf.next = function() {}

mf.controllers = {}

mf.controllers.display = function(selector) {
	var ele = $(selector)

	// currently displayed article, if any
	this.article = null

	// render a given node-feedparser article to the page
	this.render = function(article) {
		this.article = article
		$('#error').hide()
		$('#loading').hide()
		ele.css('visibility','visible')
		$('section.description',ele).html(article.description)
		$('> h1 a',ele).html(article.title).attr('href',article.origlink)
		$('time',ele).attr('datetime',article.pubdate)
		$('.note',ele).html(article.author).prepend(' by ')
		return this
	}

	var discard = this.discard = function() {
		this.article = null
		ele.css('visibility','hidden')
		return this
	}

	// show loading animation
	this.wait = function(){
		$('#loading').show()
		discard()
		$('#error').hide()
		return this
	}

	// show 'error' message
	this.error = function(msg) {
		$('#loading').hide()
		discard()
		$('#error').show().text(msg)
		return this
	}
}

// positive article counter
mf.controllers.counter = function(selector) {
	ele = $(selector)
	// count
	var value = null

	// callback for when number changes
	var change = function(from,to) {}
	this.change = function(fn) {
		change = fn
	}

	this.set = function(number) {
		if (number == value) return;
		// from, to
		change(value,number)
		ele.text(number)
		value = number
		return this
	}

	// initialise to zero without triggering change()
	ele.text(value)

	this.get = function() {
		return value
	}

	this.decrement = function() {
		if (value > 0) {
			ele.text(--value)
			change(value+1,value)
		}

		return this
	}
}

// navigation buttons (sort of like a view controller)
mf.controllers.button = function(selector){
	var ele = $(selector)
	var enabled = true;

	// callback for when button is clicked or key is pressed
	var action = function() {}
	this.action = function(fn) {
		action = fn
	}

	ele.click(function() {
		if (enabled)
			action()
	})

	this.enable = function() {
		enabled = true
		ele.removeClass('disabled')
		return this
	}

	this.disable = function() {
		enabled = false
		ele.addClass('disabled')
		return this
	}

	// bind a key
	this.bind = function(key) {

		// press
		$(document).bind('keydown',key,function() {
			if (!enabled) return false

			ele.addClass('depressed')
			return false
		})
		// release
		$(document).bind('keyup',key,function() {
			if (!enabled) return false

			ele.removeClass('depressed')
			action()
			return false
		})
		return this
	}
}

// -------model?

// download and display the next article (or current on first load)
mf.load = mf.skip = function() {
	mf.display.wait()
	mf.nav.disable()
	$.ajax({
		url: mf.display.article?'/next':'/current',
		type:'GET',
		error:function() {
			mf.display.error('No more articles')
		},
		success:function(article) {
			if (!article.pending) {
				mf.display.error('None left in queue')
				ml.article = null
			} else {
				mf.display.render(article)
				mf.nav.enable()
			}

			mf.pending.set(article.pending)
		}

	})
}

mf.publish = function() {
	mf.pending.decrement()
	$.ajax({
		url:'/publish/'+mf.display.article.id,
		type:'GET',
		error:function() {
			mf.display.error("None left!")
		},
		success:function() {
			console.log('Published article')
		}

	})
	mf.load()
}

mf.discard = function() {
	mf.pending.decrement()
	$.ajax({
		url:'/'+mf.display.article.id,
		type:'DELETE',
		error:function() {
			mf.display.error("That's it!")
		},
		success:function() {
			console.log('Deleted article')
		}

	})
	mf.load()
}

mf.inspect = function() {
	window.open(mf.display.article.link)
}

mf.nav = {}
mf.nav.enable = function() {
	mf.nav.skip.enable()
	mf.nav.discard.enable()
	mf.nav.publish.enable()
	mf.nav.inspect.enable()
}

mf.nav.disable = function() {
	mf.nav.skip.disable()
	mf.nav.discard.disable()
	mf.nav.publish.disable()
	mf.nav.inspect.disable()
}

mf.check_pending = function () {
	$.ajax({
		url: '/pending',
		type: 'GET',
		success: function(d) {
			mf.pending.set(d.pending)
		}
	})
}
<commit_msg>fix NULL counter and no article title cases<commit_after>// TODO: switch to requireJS or AMD modules
// TODO: convert to backbone?

$(function(){
	mf.init()
	mf.load()
})

var mf = {}

mf.init = function() {
	// put in constructor
	mf.nav.skip    = new mf.controllers.button('#skip')
	mf.nav.discard = new mf.controllers.button('#discard')
	mf.nav.publish = new mf.controllers.button('#publish')
	mf.nav.inspect = new mf.controllers.button('#inspect')
	mf.nav.undo    = new mf.controllers.button('#undo')

	mf.nav.skip.bind('right').bind('j').bind('s')
	mf.nav.discard.bind('x').bind('d').bind('space')
	mf.nav.publish.bind('w').bind('p')
	mf.nav.inspect.bind('i')
	mf.nav.undo.bind('u').bind('ctrl+z')
	mf.nav.undo.disable()

	mf.display = new mf.controllers.display('article')
	mf.display.wait()

	mf.pending = new mf.controllers.counter('#pending')
	// queue refill should load article
	mf.pending.change(function(from, to){
		if (from == 0 && to > 0)
			mf.load()

		document.title =  '('+to+') Megafilter'
		console.log('change to',to,'from',from)
	})

	mf.nav.skip.action(mf.skip)
	mf.nav.discard.action(mf.discard)
	mf.nav.publish.action(mf.publish)
	mf.nav.inspect.action(mf.inspect)
	//mf.nav.undo.action(mf.undo)

	setInterval(mf.check_pending,5000)
}

// render the next article from cache and begin to use the
mf.next = function() {}

mf.controllers = {}

mf.controllers.display = function(selector) {
	var ele = $(selector)

	// currently displayed article, if any
	this.article = null

	// render a given node-feedparser article to the page
	this.render = function(article) {
		this.article = article
		$('#error').hide()
		$('#loading').hide()
		ele.css('visibility','visible')
		$('section.description',ele).html(article.description)
		$('> h1 a',ele).html(article.title).attr('href',article.origlink)
		$('time',ele).attr('datetime',article.pubdate)
		if (article.author) $('.note',ele).html(article.author).prepend(' by ')
		// also do link to source site homepage
		return this
	}

	var discard = this.discard = function() {
		this.article = null
		ele.css('visibility','hidden')
		return this
	}

	// show loading animation
	this.wait = function(){
		$('#loading').show()
		discard()
		$('#error').hide()
		return this
	}

	// show 'error' message
	this.error = function(msg) {
		$('#loading').hide()
		discard()
		$('#error').show().text(msg)
		return this
	}
}

// positive article counter
mf.controllers.counter = function(selector) {
	ele = $(selector)
	// count
	var value = " "

	// callback for when number changes
	var change = function(from,to) {}
	this.change = function(fn) {
		change = fn
	}

	this.set = function(number) {
		if (number == value) return;
		// from, to
		change(value,number)
		ele.text(number)
		value = number
		return this
	}

	// initialise to zero without triggering change()
	ele.text(value)

	this.get = function() {
		return value
	}

	this.decrement = function() {
		if (value > 0) {
			ele.text(--value)
			change(value+1,value)
		}

		return this
	}
}

// navigation buttons (sort of like a view controller)
mf.controllers.button = function(selector){
	var ele = $(selector)
	var enabled = true;

	// callback for when button is clicked or key is pressed
	var action = function() {}
	this.action = function(fn) {
		action = fn
	}

	ele.click(function() {
		if (enabled)
			action()
	})

	this.enable = function() {
		enabled = true
		ele.removeClass('disabled')
		return this
	}

	this.disable = function() {
		enabled = false
		ele.addClass('disabled')
		return this
	}

	// bind a key
	this.bind = function(key) {

		// press
		$(document).bind('keydown',key,function() {
			if (!enabled) return false

			ele.addClass('depressed')
			return false
		})
		// release
		$(document).bind('keyup',key,function() {
			if (!enabled) return false

			ele.removeClass('depressed')
			action()
			return false
		})
		return this
	}
}

// -------model?

// download and display the next article (or current on first load)
mf.load = mf.skip = function() {
	mf.display.wait()
	mf.nav.disable()
	$.ajax({
		url: mf.display.article?'/next':'/current',
		type:'GET',
		error:function() {
			mf.display.error('No more articles')
		},
		success:function(article) {
			if (!article.pending) {
				mf.display.error('None left in queue')
				ml.article = null
			} else {
				mf.display.render(article)
				mf.nav.enable()
			}

			mf.pending.set(article.pending)
		}

	})
}

mf.publish = function() {
	mf.pending.decrement()
	$.ajax({
		url:'/publish/'+mf.display.article.id,
		type:'GET',
		error:function() {
			mf.display.error("None left!")
		},
		success:function() {
			console.log('Published article')
		}

	})
	mf.load()
}

mf.discard = function() {
	mf.pending.decrement()
	$.ajax({
		url:'/'+mf.display.article.id,
		type:'DELETE',
		error:function() {
			mf.display.error("That's it!")
		},
		success:function() {
			console.log('Deleted article')
		}

	})
	mf.load()
}

mf.inspect = function() {
	window.open(mf.display.article.link)
}

mf.nav = {}
mf.nav.enable = function() {
	mf.nav.skip.enable()
	mf.nav.discard.enable()
	mf.nav.publish.enable()
	mf.nav.inspect.enable()
}

mf.nav.disable = function() {
	mf.nav.skip.disable()
	mf.nav.discard.disable()
	mf.nav.publish.disable()
	mf.nav.inspect.disable()
}

mf.check_pending = function () {
	$.ajax({
		url: '/pending',
		type: 'GET',
		success: function(d) {
			mf.pending.set(d.pending)
		}
	})
}
<|endoftext|>


<commit_before>import utils from './utils';
import {
  CLASSNAME,
  VARS,
  eventType as EVENT_TYPE
} from './constants';

/**
 * @class Internal
 */
export class Internal {
  constructor(base) {
    this.Base = base;

    this.container = base.container.element;

    // ready to close when both are chosen
    this.closeWhen = { hour: false, minute: false };

    // increment internal ids
    this._ids = 0;

    // active picker
    this.id_active = undefined;

    // is this opened
    this.opened = false;

    // these are targets we're working on
    this.targets = [];

    // this will cache DOM <a> hours (and minutes) array among others
    this.collection = {
      hours: [],
      minutes: []
    };

    this.events = utils.events();

    this.request_ani_id = undefined;
  }

  init() {
    this.setFocusListener(this.Base.target);
    this.setSelectListener();
  }

  show(id) {
    const target = this.targets[id].element;
    const target_offset = utils.offset(target);
    const container_offset = this.Base.container.size;
    const top = target_offset.top + target_offset.height + 5;
    const window_ = utils.getWindowSize();

    if (target_offset.left + container_offset.width > window_.width) {
      this.container.style.left = '';
      this.container.style.right = '5px';
    } else {
      this.container.style.right = '';
      this.container.style.left = target_offset.left + 'px';
    }

    if (target_offset.top + container_offset.height > window_.height) {
      this.container.style.bottom = '5px';
    } else {
      this.container.style.top = top + 'px';
    }

    this.events.subscribe(EVENT_TYPE.start_fade_in, obj => {
      obj.target.style.opacity = 0;
      obj.target.style.display = 'block';
    });

    this.request_ani_id = utils.fade(this.events, this.container, 400);
    this.Base.dispatchEvent(EVENT_TYPE.open, { element: target });
    this.handleOpen(id);
  }

  show_() {
    this.targets.forEach(each => { this.show(each.element._id); });
  }

  hide(id) {
    this.opened = false;
    this.events.subscribe(EVENT_TYPE.start_fade_out, obj => {
      obj.target.style.opacity = 1;
      obj.target.style.display = 'block';
    });
    this.events.subscribe(EVENT_TYPE.end_fade_out, obj => {
      obj.target.style.display = 'none';
    });
    this.request_ani_id = utils.fade(this.events, this.container, 800, 'out');
    console.warn(this.targets);
    console.warn(id);
    this.Base.dispatchEvent(EVENT_TYPE.close, {
      element: this.targets[id].element
    });
  }

  hide_() {
    this.targets.forEach(each => { console.warn(each); this.hide(each.element._id); });
  }

  handleOpen(id) {
    const this_ = this;
    const hour = this.targets[id].hour;
    const minute = this.targets[id].minute;
    let value;

    utils.removeClass(this.collection.hours, CLASSNAME.selected);
    utils.removeClass(this.collection.minutes, CLASSNAME.selected);

    if (hour && minute) {
      this.collection.hours.forEach(element => {
        value = this.getHour(element);
        if (value === hour) {
          utils.addClass(element, CLASSNAME.selected);
          return;
        }
      });
      this.collection.minutes.forEach(element => {
        value = this.getMinute(element);
        if (value === minute) {
          utils.addClass(element, CLASSNAME.selected);
          return;
        }
      });
    }

    //one-time fire
    document.addEventListener('mousedown', {
      handleEvent: function (evt) {
        // click inside Picker
        if (this_.container.contains(evt.target)) return;

        let is_clicking_target = false;
        this_.targets.forEach(target => {
          if (target.element === evt.target) is_clicking_target = true;
        });

        if (!is_clicking_target && this_.opened) this_.hide(id);

        if (this_.targets[id].element !== evt.target) {
          document.removeEventListener(evt.type, this, false);
        }
      }
    }, false);

    this.opened = true;
    this.id_active = id;
    this.closeWhen = {
      hour: false,
      minute: false
    };
  }

  handleClose(id) {
    if (this.closeWhen.hour && this.closeWhen.minute) this.hide(id);
  }

  getHour(element) {
    return element.getAttribute(VARS.attr.hour);
  }

  getMinute(element) {
    return element.getAttribute(VARS.attr.minute);
  }

  setSelectListener() {
    const hour_list = utils.$(VARS.ids.hour_list);
    const minute_list = utils.$(VARS.ids.minute_list);
    const selectHour = evt => {
      evt.preventDefault();
      const active = this.targets[this.id_active];

      active.hour = this.getHour(evt.target);
      this.Base.dispatchEvent(EVENT_TYPE.change, {
        element: active.element,
        hour: active.hour,
        minute: active.minute
      });

      utils.removeClass(this.collection.hours, CLASSNAME.selected);
      utils.addClass(evt.target, CLASSNAME.selected);
      this.closeWhen.hour = true;
      this.handleClose(this.id_active);
    };
    const selectMinute = evt => {
      evt.preventDefault();
      const active = this.targets[this.id_active];

      active.minute = this.getMinute(evt.target);
      this.Base.dispatchEvent(EVENT_TYPE.change, {
        element: active.element,
        hour: active.hour,
        minute: active.minute
      });

      utils.removeClass(this.collection.minutes, CLASSNAME.selected);
      utils.addClass(evt.target, CLASSNAME.selected);
      this.closeWhen.minute = true;
      this.handleClose(this.id_active);
    };

    this.collection.hours = utils.getAllChildren(hour_list, 'a');
    this.collection.minutes = utils.getAllChildren(minute_list, 'a');

    this.collection.hours.forEach(hour => {
      hour.addEventListener('click', selectHour);
    });
    this.collection.minutes.forEach(minute => {
      minute.addEventListener('click', selectMinute);
    });
  }

  setFocusListener(target) {
    const triggerShow = evt => {
      evt.preventDefault();
      window.cancelAnimationFrame(this.request_ani_id);
      this.show(evt.target._id);
    };

    let ar_target = [], element;
    // to array if string
    target = Array.isArray(target) ? target : [target];
    // merge
    Array.prototype.push.apply(ar_target, target);

    ar_target.forEach(el => {
      element = utils.evaluate(el);
      if (!element) return;

      let id = this._ids++;
      element._id = id;
      this.targets[id] = { element: element };

      if (utils.focusable.test(element.nodeName)) {
        element.addEventListener('focus', triggerShow, true);
      } else if (utils.clickable.test(element.nodeName)) {
        element.addEventListener('click', triggerShow, true);
      }
    });
  }
}
<commit_msg>Remove console.log<commit_after>import utils from './utils';
import {
  CLASSNAME,
  VARS,
  eventType as EVENT_TYPE
} from './constants';

/**
 * @class Internal
 */
export class Internal {
  constructor(base) {
    this.Base = base;

    this.container = base.container.element;

    // ready to close when both are chosen
    this.closeWhen = { hour: false, minute: false };

    // increment internal ids
    this._ids = 0;

    // active picker
    this.id_active = undefined;

    // is this opened
    this.opened = false;

    // these are targets we're working on
    this.targets = [];

    // this will cache DOM <a> hours (and minutes) array among others
    this.collection = {
      hours: [],
      minutes: []
    };

    this.events = utils.events();

    this.request_ani_id = undefined;
  }

  init() {
    this.setFocusListener(this.Base.target);
    this.setSelectListener();
  }

  show(id) {
    const target = this.targets[id].element;
    const target_offset = utils.offset(target);
    const container_offset = this.Base.container.size;
    const top = target_offset.top + target_offset.height + 5;
    const window_ = utils.getWindowSize();

    if (target_offset.left + container_offset.width > window_.width) {
      this.container.style.left = '';
      this.container.style.right = '5px';
    } else {
      this.container.style.right = '';
      this.container.style.left = target_offset.left + 'px';
    }

    if (target_offset.top + container_offset.height > window_.height) {
      this.container.style.bottom = '5px';
    } else {
      this.container.style.top = top + 'px';
    }

    this.events.subscribe(EVENT_TYPE.start_fade_in, obj => {
      obj.target.style.opacity = 0;
      obj.target.style.display = 'block';
    });

    this.request_ani_id = utils.fade(this.events, this.container, 400);
    this.Base.dispatchEvent(EVENT_TYPE.open, { element: target });
    this.handleOpen(id);
  }

  show_() {
    this.targets.forEach(each => { this.show(each.element._id); });
  }

  hide(id) {
    this.opened = false;
    this.events.subscribe(EVENT_TYPE.start_fade_out, obj => {
      obj.target.style.opacity = 1;
      obj.target.style.display = 'block';
    });
    this.events.subscribe(EVENT_TYPE.end_fade_out, obj => {
      obj.target.style.display = 'none';
    });
    this.request_ani_id = utils.fade(this.events, this.container, 800, 'out');
    this.Base.dispatchEvent(EVENT_TYPE.close, {
      element: this.targets[id].element
    });
  }

  hide_() {
    this.targets.forEach(each => { this.hide(each.element._id); });
  }

  handleOpen(id) {
    const this_ = this;
    const hour = this.targets[id].hour;
    const minute = this.targets[id].minute;
    let value;

    utils.removeClass(this.collection.hours, CLASSNAME.selected);
    utils.removeClass(this.collection.minutes, CLASSNAME.selected);

    if (hour && minute) {
      this.collection.hours.forEach(element => {
        value = this.getHour(element);
        if (value === hour) {
          utils.addClass(element, CLASSNAME.selected);
          return;
        }
      });
      this.collection.minutes.forEach(element => {
        value = this.getMinute(element);
        if (value === minute) {
          utils.addClass(element, CLASSNAME.selected);
          return;
        }
      });
    }

    //one-time fire
    document.addEventListener('mousedown', {
      handleEvent: function (evt) {
        // click inside Picker
        if (this_.container.contains(evt.target)) return;

        let is_clicking_target = false;
        this_.targets.forEach(target => {
          if (target.element === evt.target) is_clicking_target = true;
        });

        if (!is_clicking_target && this_.opened) this_.hide(id);

        if (this_.targets[id].element !== evt.target) {
          document.removeEventListener(evt.type, this, false);
        }
      }
    }, false);

    this.opened = true;
    this.id_active = id;
    this.closeWhen = {
      hour: false,
      minute: false
    };
  }

  handleClose(id) {
    if (this.closeWhen.hour && this.closeWhen.minute) this.hide(id);
  }

  getHour(element) {
    return element.getAttribute(VARS.attr.hour);
  }

  getMinute(element) {
    return element.getAttribute(VARS.attr.minute);
  }

  setSelectListener() {
    const hour_list = utils.$(VARS.ids.hour_list);
    const minute_list = utils.$(VARS.ids.minute_list);
    const selectHour = evt => {
      evt.preventDefault();
      const active = this.targets[this.id_active];

      active.hour = this.getHour(evt.target);
      this.Base.dispatchEvent(EVENT_TYPE.change, {
        element: active.element,
        hour: active.hour,
        minute: active.minute
      });

      utils.removeClass(this.collection.hours, CLASSNAME.selected);
      utils.addClass(evt.target, CLASSNAME.selected);
      this.closeWhen.hour = true;
      this.handleClose(this.id_active);
    };
    const selectMinute = evt => {
      evt.preventDefault();
      const active = this.targets[this.id_active];

      active.minute = this.getMinute(evt.target);
      this.Base.dispatchEvent(EVENT_TYPE.change, {
        element: active.element,
        hour: active.hour,
        minute: active.minute
      });

      utils.removeClass(this.collection.minutes, CLASSNAME.selected);
      utils.addClass(evt.target, CLASSNAME.selected);
      this.closeWhen.minute = true;
      this.handleClose(this.id_active);
    };

    this.collection.hours = utils.getAllChildren(hour_list, 'a');
    this.collection.minutes = utils.getAllChildren(minute_list, 'a');

    this.collection.hours.forEach(hour => {
      hour.addEventListener('click', selectHour);
    });
    this.collection.minutes.forEach(minute => {
      minute.addEventListener('click', selectMinute);
    });
  }

  setFocusListener(target) {
    const triggerShow = evt => {
      evt.preventDefault();
      window.cancelAnimationFrame(this.request_ani_id);
      this.show(evt.target._id);
    };

    let ar_target = [], element;
    // to array if string
    target = Array.isArray(target) ? target : [target];
    // merge
    Array.prototype.push.apply(ar_target, target);

    ar_target.forEach(el => {
      element = utils.evaluate(el);
      if (!element) return;

      let id = this._ids++;
      element._id = id;
      this.targets[id] = { element: element };

      if (utils.focusable.test(element.nodeName)) {
        element.addEventListener('focus', triggerShow, true);
      } else if (utils.clickable.test(element.nodeName)) {
        element.addEventListener('click', triggerShow, true);
      }
    });
  }
}
<|endoftext|>