<commit_before>function editRelated (collectionId, data, templateData, field, idField) {
  var list = templateData[field];
  if (idField === 'article') {
    var dataTemplate = {list: list, idField: idField, idPlural: 'articles'};
  } else if (idField === 'bulletin') {
    var dataTemplate = {list: list, idField: idField, idPlural: 'bulletins'};
  } else if (idField === 'dataset') {
    var dataTemplate = {list: list, idField: idField, idPlural: 'datasets'};
  } else if (idField === 'document') {
    var dataTemplate = {list: list, idField: idField, idPlural: 'documents'};
  } else if (idField === 'methodology') {
    var dataTemplate = {list: list, idField: idField, idPlural: 'methodologies'};
  } else {
    var dataTemplate = {list: list, idField: idField};
  }
  var html = templates.editorRelated(dataTemplate);
  $('#'+ idField).replaceWith(html);
  // Load
  if (!data[field] || data[field].length === 0) {
    editRelated['lastIndex' + field] = 0;
  } else {
    $(data[field]).each(function (index, value) {
      editRelated['lastIndex' + field] = index + 1;

      // Delete
      $('#' + idField + '-delete_' + index).click(function () {
        var result = confirm("Are you sure you want to delete this link?");
        if (result === true) {
          var position = $(".workspace-edit").scrollTop();
          localStorage.setItem("pagePos", position);
          $(this).parent().remove();
          data[field].splice(index, 1);
          postContent(collectionId, data.uri, JSON.stringify(data),
            success = function (response) {
              Florence.Editor.isDirty = false;
              refreshPreview(data.uri);
              editRelated (collectionId, data, field, idField);
            },
            error = function (response) {
              if (response.status === 400) {
                alert("Cannot edit this file. It is already part of another collection.");
              }
              else if (response.status === 401) {
                alert("You are not authorised to update content.");
              }
              else {
                handleApiError(response);
              }
            }
          );
        }
      });
    });
  }

  //Add
  $('#add-' + idField).one('click', function () {
    var position = $(".workspace-edit").scrollTop();
    localStorage.setItem("pagePos", position);
    var iframeEvent = document.getElementById('iframe').contentWindow;
        iframeEvent.removeEventListener('click', Florence.Handler, true);
    createWorkspace(data.uri, collectionId, '', true);

    $('#sortable-' + idField).append(
        '
' +
        '  <textarea id="' + idField + '-uri_' + editRelated['lastIndex' + field] + '" placeholder="Go to the related data and click Get"></textarea>' +
        '  <button class="btn-page-get" id="' + idField + '-get_' + editRelated['lastIndex' + field] + '">Get</button>' +
        '  <button class="btn-page-cancel" id="' + idField + '-cancel_' + editRelated['lastIndex' + field] + '">Cancel</button>' +
        '
').trigger('create');

    $('#' + idField + '-cancel_' + editRelated['lastIndex' + field]).one('click', function () {
      createWorkspace(data.uri, collectionId, 'edit');
    });

    $('#' + idField + '-get_' + editRelated['lastIndex' + field]).one('click', function () {
      var pastedUrl = $('#' + idField + '-uri_'+editRelated['lastIndex' + field]).val();
      if (pastedUrl) {
        checkPathParsed(pastedUrl);
        var dataUrlData = pastedUrl + "/data";
      } else {
        var dataUrl = getPathNameTrimLast();
        checkPathParsed(dataUrl);
        var dataUrlData = dataUrl + "/data";
      }

      $.ajax({
        url: dataUrlData,
        dataType: 'json',
        crossDomain: true,
        success: function (result) {
          if ((field === 'relatedBulletins' || field === 'statsBulletins') && result.type === 'bulletin') {
            if (!data[field]) {
              data[field] = [];
            }
          }

          else if (field === 'relatedArticles' && result.type === 'article') {
            if (!data[field]) {
              data[field] = [];
            }
          }

          else if ((field === 'relatedDocuments') && (result.type === 'article' || result.type === 'bulletin')) {
            if (!data[field]) {
              data[field] = [];
            }
          }

          else if ((field === 'relatedDatasets' || field === 'datasets') && (result.type === 'dataset' || result.type === 'reference_tables')) {
            if (!data[field]) {
              data[field] = [];
            }
          }

          else if ((field === 'items') && (result.type === 'timeseries')) {
            if (!data[field]) {
              data[field] = [];
            }
          }

          else if ((field === 'relatedData') && (result.type === 'timeseries' || result.type === 'dataset' || result.type === 'reference_tables')) {
            if (!data[field]) {
              data[field] = [];
            }
          }

          else if (field === 'relatedMethodology' && result.type === 'static_methodology') {
            if (!data[field]) {
              data[field] = [];
            }
          }

          else {
            alert("This is not a valid document");
            return;
          }

          data[field].push({uri: result.uri});
          saveRelated(collectionId, data.uri, data, field, idField);

        },
        error: function () {
          console.log('No page data returned');
        }
      });
    });
  });

  function sortable() {
    $('#sortable-' + idField).sortable();
  }
  sortable();
}

<commit_msg>Add compendium to related documents<commit_after>function editRelated (collectionId, data, templateData, field, idField) {
  var list = templateData[field];
  if (idField === 'article') {
    var dataTemplate = {list: list, idField: idField, idPlural: 'articles'};
  } else if (idField === 'bulletin') {
    var dataTemplate = {list: list, idField: idField, idPlural: 'bulletins'};
  } else if (idField === 'dataset') {
    var dataTemplate = {list: list, idField: idField, idPlural: 'datasets'};
  } else if (idField === 'document') {
    var dataTemplate = {list: list, idField: idField, idPlural: 'documents'};
  } else if (idField === 'methodology') {
    var dataTemplate = {list: list, idField: idField, idPlural: 'methodologies'};
  } else {
    var dataTemplate = {list: list, idField: idField};
  }
  var html = templates.editorRelated(dataTemplate);
  $('#'+ idField).replaceWith(html);
  // Load
  if (!data[field] || data[field].length === 0) {
    editRelated['lastIndex' + field] = 0;
  } else {
    $(data[field]).each(function (index, value) {
      editRelated['lastIndex' + field] = index + 1;

      // Delete
      $('#' + idField + '-delete_' + index).click(function () {
        var result = confirm("Are you sure you want to delete this link?");
        if (result === true) {
          var position = $(".workspace-edit").scrollTop();
          localStorage.setItem("pagePos", position);
          $(this).parent().remove();
          data[field].splice(index, 1);
          postContent(collectionId, data.uri, JSON.stringify(data),
            success = function (response) {
              Florence.Editor.isDirty = false;
              refreshPreview(data.uri);
              editRelated (collectionId, data, field, idField);
            },
            error = function (response) {
              if (response.status === 400) {
                alert("Cannot edit this file. It is already part of another collection.");
              }
              else if (response.status === 401) {
                alert("You are not authorised to update content.");
              }
              else {
                handleApiError(response);
              }
            }
          );
        }
      });
    });
  }

  //Add
  $('#add-' + idField).one('click', function () {
    var position = $(".workspace-edit").scrollTop();
    localStorage.setItem("pagePos", position);
    var iframeEvent = document.getElementById('iframe').contentWindow;
        iframeEvent.removeEventListener('click', Florence.Handler, true);
    createWorkspace(data.uri, collectionId, '', true);

    $('#sortable-' + idField).append(
        '
' +
        '  <textarea id="' + idField + '-uri_' + editRelated['lastIndex' + field] + '" placeholder="Go to the related data and click Get"></textarea>' +
        '  <button class="btn-page-get" id="' + idField + '-get_' + editRelated['lastIndex' + field] + '">Get</button>' +
        '  <button class="btn-page-cancel" id="' + idField + '-cancel_' + editRelated['lastIndex' + field] + '">Cancel</button>' +
        '
').trigger('create');

    $('#' + idField + '-cancel_' + editRelated['lastIndex' + field]).one('click', function () {
      createWorkspace(data.uri, collectionId, 'edit');
    });

    $('#' + idField + '-get_' + editRelated['lastIndex' + field]).one('click', function () {
      var pastedUrl = $('#' + idField + '-uri_'+editRelated['lastIndex' + field]).val();
      if (pastedUrl) {
        checkPathParsed(pastedUrl);
        var dataUrlData = pastedUrl + "/data";
      } else {
        var dataUrl = getPathNameTrimLast();
        checkPathParsed(dataUrl);
        var dataUrlData = dataUrl + "/data";
      }

      $.ajax({
        url: dataUrlData,
        dataType: 'json',
        crossDomain: true,
        success: function (result) {
          if ((field === 'relatedBulletins' || field === 'statsBulletins') && result.type === 'bulletin') {
            if (!data[field]) {
              data[field] = [];
            }
          }

          else if (field === 'relatedArticles' && result.type === 'article') {
            if (!data[field]) {
              data[field] = [];
            }
          }

          else if ((field === 'relatedDocuments') && (result.type === 'article' || result.type === 'bulletin' || result.type === 'compendium_landing_page')) {
            if (!data[field]) {
              data[field] = [];
            }
          }

          else if ((field === 'relatedDatasets' || field === 'datasets') && (result.type === 'dataset' || result.type === 'reference_tables')) {
            if (!data[field]) {
              data[field] = [];
            }
          }

          else if ((field === 'items') && (result.type === 'timeseries')) {
            if (!data[field]) {
              data[field] = [];
            }
          }

          else if ((field === 'relatedData') && (result.type === 'timeseries' || result.type === 'dataset' || result.type === 'reference_tables')) {
            if (!data[field]) {
              data[field] = [];
            }
          }

          else if (field === 'relatedMethodology' && result.type === 'static_methodology') {
            if (!data[field]) {
              data[field] = [];
            }
          }

          else {
            alert("This is not a valid document");
            return;
          }

          data[field].push({uri: result.uri});
          saveRelated(collectionId, data.uri, data, field, idField);

        },
        error: function () {
          console.log('No page data returned');
        }
      });
    });
  });

  function sortable() {
    $('#sortable-' + idField).sortable();
  }
  sortable();
}

<|endoftext|>


<commit_before>/**
 * Client to connect to a darkwallet gateway.
 *
 * @param {String}   connect_uri Gateway websocket URI
 * @param {Function} handle_connect Callback to run when connected
 * @param {Function} handle_disconnect Callback to run when disconnected
 * @param {Function} handle_error Callback to run on errors (except connection errors go to handle_connect first parameter).
 *
 * handle_* callbacks take parameters as (error, data)
 */
function GatewayClient(connect_uri, handle_connect, handle_disconnect, handle_error) {
    var self = this;
    this.handler_map = {};
    this.connected = false;
    this.websocket = new WebSocket(connect_uri);
    var closingCb;
    this.close = function(_cb) {
        self.connected = false;
        self.handler_map = {};
        closingCb = _cb;
        self.websocket.close();
    };
    this.websocket.onopen = function(evt) {
        self.connected = true;
        handle_connect();
    };
    this.websocket.onclose = function(evt) {
        self.connected = false;
        self.on_close(evt);
        if (handle_disconnect) {
            handle_disconnect(null, evt)
        }
        if (closingCb) {
            closingCb();
            closingCb = false;
        }
    };
    this.websocket.onerror = function(evt) {
        // TODO: should probably disconnect
        if (!self.connected) {
            handle_connect(evt);
        } else if (handle_error) {
            handle_error(evt);
        }
    };
    this.websocket.onmessage = function(evt) {
        self._on_message(evt);
    };
}

/**
 * Get last height
 *
 * @param {Function} handle_fetch Callback to handle the returned height
 */
GatewayClient.prototype.fetch_last_height = function(handle_fetch) {
    GatewayClient._check_function(handle_fetch);

    this.make_request("fetch_last_height", [], function(response) {
        handle_fetch(response["error"], response["result"][0]);
    });
};

/**
 * Fetch transaction
 *
 * @param {String}   tx_hash Transaction identifier hash
 * @param {Function} handle_fetch Callback to handle the JSON object
 * representing the transaction
 */
GatewayClient.prototype.fetch_transaction = function(tx_hash, handle_fetch) {
    GatewayClient._check_function(handle_fetch);

    this.make_request("fetch_transaction", [tx_hash], function(response) {
        handle_fetch(response["error"], response["result"][0]);
    });
};

/**
 * Fetch history
 *
 * @param {String}   address
 * @param {Function} handle_fetch Callback to handle the JSON object
 * representing the history of the address
 */
GatewayClient.prototype.fetch_history = function(address, height, handle_fetch) {
    height = height || 0;
    GatewayClient._check_function(handle_fetch);

    this.make_request("fetch_history", [address, height], function(response) {
        handle_fetch(response["error"], response["result"][0]);
    });
};

GatewayClient.prototype.fetch_stealth = function(
    prefix, handle_fetch, from_height)
{
    GatewayClient._check_function(handle_fetch);

    this.make_request("fetch_stealth", [prefix, from_height],
        function(response) {
            handle_fetch(response["error"], response["result"][0]);
        });
};

/**
 * Subscribe
 *
 * @param {String}   address
 * @param {Function} handle_fetch Callback to handle subscription result
 * @param {Function} handle_update Callback to handle the JSON object
 * representing for updates
 */
GatewayClient.prototype.subscribe = function(
    address, handle_fetch, handle_update)
{
    var self = this;
    this.make_request("subscribe_address", [address], function(response) {
        handle_fetch(response["error"], response["result"][0]);
        if (handle_update) {
            self.handler_map["update." + address] = handle_update;
        }
    });
}

/**
 * Unsubscribe
 *
 * @param {String}   address
 * @param {Function} handle_fetch Callback to handle subscription result
 * representing for updates
 */

GatewayClient.prototype.unsubscribe = function(address, handle_fetch)
{
    if (this.handler_map["update." + address]) {
        delete this.handler_map["update." + address];
    }
    this.make_request("unsubscribe_address", [address], function(response) {
        handle_fetch(response["error"], response["result"][0]);
    });
}

GatewayClient.prototype.fetch_block_header = function(index, handle_fetch) {
    GatewayClient._check_function(handle_fetch);

    this.make_request("fetch_block_header", [index], function(response) {
        handle_fetch(response["error"], response["result"][0]);
    });
};

GatewayClient.prototype.fetch_block_transaction_hashes = function(
    index, handle_fetch)
{
    GatewayClient._check_function(handle_fetch);

    this.make_request("fetch_block_transaction_hashes", [index],
        function(response) {
            handle_fetch(response["error"], response["result"][0]);
        });
};

GatewayClient.prototype.fetch_spend = function(outpoint, handle_fetch) {
    GatewayClient._check_function(handle_fetch);

    this.make_request("fetch_spend", [outpoint], function(response) {
        handle_fetch(response["error"], response["result"][0]);
    });
};

GatewayClient.prototype.fetch_transaction_index = function(
    tx_hash, handle_fetch)
{
    GatewayClient._check_function(handle_fetch);

    this.make_request("fetch_transaction_index", [tx_hash],
        function(response) {
            result = response["result"];
            handle_fetch(response["error"], result[0], result[1]);
        });
};

GatewayClient.prototype.fetch_block_height = function(blk_hash, handle_fetch)
{
    GatewayClient._check_function(handle_fetch);

    this.make_request("fetch_block_height", [blk_hash], function(response) {
        handle_fetch(response["error"], response["result"][0]);
    });
};

GatewayClient.prototype.broadcast_transaction = function(
    raw_tx, handle_fetch)
{
    GatewayClient._check_function(handle_fetch);

    this.make_request("broadcast_transaction", [raw_tx], function(response) {
        handle_fetch(response["error"], response["result"][0]);
    });
};

/**
 * Renew
 *
 * @param {String}   address
 * @param {Function} handle_fetch Callback to handle subscription result
 * @param {Function} handle_update Callback to handle the JSON object
 * representing for updates
 */
GatewayClient.prototype.renew = function(address, handle_fetch, handle_update)
{
    var self = this;
    this.make_request("renew_address", [address], function(response) {
        handle_fetch(response["error"], response["result"][0]);
        if (handle_update) {
            self.handler_map["update."+address] = handle_update;
        }
    });
}

/**
 * Chan functionality
 */
GatewayClient.prototype.chan_post = function(section_name, thread_id, data, handle_fetch) {
    GatewayClient._check_function(handle_fetch);

    this.make_request("chan_post", [section_name, thread_id, data], function(response) {
        if (handle_fetch)
            //console.log("raw chan post", response["result"]);
            handle_fetch(response["error"], response["result"]);
    });
};

GatewayClient.prototype.chan_list = function(section_name, handle_fetch) {
    GatewayClient._check_function(handle_fetch);

    this.make_request("chan_list", [section_name], function(response) {
        if (handle_fetch)
            handle_fetch(response["error"], response["result"]);
    });
};

GatewayClient.prototype.chan_get = function(section_name, thread_id, handle_fetch) {
    GatewayClient._check_function(handle_fetch);

    this.make_request("chan_get", [section_name, thread_id], function(response) {
        if (handle_fetch)
            handle_fetch(response["error"], response["result"]);
    });
};

GatewayClient.prototype.chan_subscribe = function(section_name, thread_id, handle_fetch, handle_update) {
    GatewayClient._check_function(handle_fetch);
    var self = this;
    this.make_request("chan_subscribe", [section_name, thread_id], function(response) {
        if (handle_fetch)
            handle_fetch(response["error"], response["result"]);
        if (handle_update) {
            self.handler_map["chan.update." + thread_id] = handle_update;
        }

    });
};
GatewayClient.prototype.chan_unsubscribe = function(section_name, thread_id, handle_fetch, handle_update) {
    GatewayClient._check_function(handle_fetch);
    var self = this;
    this.make_request("chan_unsubscribe", [section_name, thread_id], function(response) {
        if (handle_fetch)
            handle_fetch(response["error"], response["result"]);
        if (self.handler_map["chan.update." + thread_id]) {
            delete self.handler_map["chan.update." + thread_id]
        }
    });
};

/**
 * Ticker functionality
 *
 * @param {String} currency, like USD, EUR...
 * @param {Function} handle_fetch
 */

GatewayClient.prototype.fetch_ticker = function(currency, handle_fetch)
{
    GatewayClient._check_function(handle_fetch);

    this.make_request("fetch_ticker", [currency], function(response) {
        handle_fetch(response["error"], response["result"][0]);
    });
};

/**
 * Make requests to the server
 *
 * @param {String} command
 * @param {Array} params
 * @param {Function} handler
 */
GatewayClient.prototype.make_request = function(command, params, handler) {
    GatewayClient._check_function(handler);

    var id = GatewayClient._random_integer();
    var request = {
        "id": id,
        "command": command,
        "params": params
    };
    var message = JSON.stringify(request);
    this.websocket.send(message);
    this.handler_map[id] = handler;
};

/**
 * Close event handler
 *
 * @param {Object} evt event
 */
GatewayClient.prototype.on_close = function(evt) {
};

/**
 * Error event handler
 *
 * @param {Object} evt event
 *
 * @throws {Object}
 */
GatewayClient.prototype.on_error = function(evt) {
    throw evt;
};

/**
 * After triggering message event, calls to the handler of the petition
 *
 * @param {Object} evt event
 * @private
 */
GatewayClient.prototype._on_message = function(evt) {
    this.on_message(evt)
    response = JSON.parse(evt.data);
    id = response.id;
    // Should be a separate map entirely. This is a hack.
    if (response.type == "update")
        id = "update." + response.address;
    if (response.type == "chan_update")
        id = "chan.update." + response.thread;
    // Prefer flat code over nested.
    if (!this.handler_map[id]) {
        console.log("Handler not found", id);
        return;
    }
    handler = this.handler_map[id];
    handler(response);
};

/**
 * Message event handler
 *
 * @param {Object} evt event
 */
GatewayClient.prototype.on_message = function(evt) {
}

/**
 * (Pseudo-)Random integer generator
 *
 * @return {Number} Random integer
 * @private
 */
GatewayClient._random_integer = function() {
    return Math.floor((Math.random() * 4294967296));
};

/**
 * Checks if param can be executed
 *
 * @param {Function} Function to be checked
 *
 * @throws {String} Parameter is not a function
 * @protected
 */
GatewayClient._check_function = function(func) {
    if (typeof func !== 'function') {
        throw "Parameter is not a function";
    }
};

<commit_msg>Upstream update.<commit_after>/**
 * Client to connect to a darkwallet gateway.
 *
 * @param {String}   connect_uri Gateway websocket URI
 * @param {Function} handle_connect Callback to run when connected
 * @param {Function} handle_disconnect Callback to run when disconnected
 * @param {Function} handle_error Callback to run on errors (except connection errors go to handle_connect first parameter).
 *
 * handle_* callbacks take parameters as (error, data)
 */
function GatewayClient(connect_uri, handle_connect, handle_disconnect, handle_error) {
    var self = this;
    this.handler_map = {};
    this.connected = false;
    this.websocket = new WebSocket(connect_uri);
    var closingCb;
    this.close = function(_cb) {
        self.connected = false;
        self.handler_map = {};
        closingCb = _cb;
        self.websocket.close();
    };
    this.websocket.onopen = function(evt) {
        self.connected = true;
        handle_connect();
    };
    this.websocket.onclose = function(evt) {
        self.connected = false;
        self.on_close(evt);
        if (handle_disconnect) {
            handle_disconnect(null, evt)
        }
        if (closingCb) {
            closingCb();
            closingCb = false;
        }
    };
    this.websocket.onerror = function(evt) {
        // TODO: should probably disconnect
        if (!self.connected) {
            handle_connect(evt);
        } else if (handle_error) {
            handle_error(evt);
        }
    };
    this.websocket.onmessage = function(evt) {
        self._on_message(evt);
    };
}

/**
 * Get last height
 *
 * @param {Function} handle_fetch Callback to handle the returned height
 */
GatewayClient.prototype.fetch_last_height = function(handle_fetch) {
    GatewayClient._check_function(handle_fetch);

    this.make_request("fetch_last_height", [], function(response) {
        handle_fetch(response["error"], response["result"][0]);
    });
};

/**
 * Fetch transaction
 *
 * @param {String}   tx_hash Transaction identifier hash
 * @param {Function} handle_fetch Callback to handle the JSON object
 * representing the transaction
 */
GatewayClient.prototype.fetch_transaction = function(tx_hash, handle_fetch) {
    GatewayClient._check_function(handle_fetch);

    this.make_request("fetch_transaction", [tx_hash], function(response) {
        handle_fetch(response["error"], response["result"][0]);
    });
};

/**
 * Fetch history
 *
 * @param {String}   address
 * @param {Function} handle_fetch Callback to handle the JSON object
 * representing the history of the address
 */
GatewayClient.prototype.fetch_history = function(address, height, handle_fetch) {
    height = height || 0;
    GatewayClient._check_function(handle_fetch);

    this.make_request("fetch_history", [address, height], function(response) {
        handle_fetch(response["error"], response["result"][0]);
    });
};

GatewayClient.prototype.fetch_stealth = function(
    prefix, handle_fetch, from_height)
{
    GatewayClient._check_function(handle_fetch);

    this.make_request("fetch_stealth", [prefix, from_height],
        function(response) {
            handle_fetch(response["error"], response["result"][0]);
        });
};

/**
 * Subscribe
 *
 * @param {String}   address
 * @param {Function} handle_fetch Callback to handle subscription result
 * @param {Function} handle_update Callback to handle the JSON object
 * representing for updates
 */
GatewayClient.prototype.subscribe = function(
    address, handle_fetch, handle_update)
{
    var self = this;
    this.make_request("subscribe_address", [address], function(response) {
        handle_fetch(response["error"], response["result"][0]);
        if (handle_update) {
            self.handler_map["update." + address] = handle_update;
        }
    });
}

/**
 * Unsubscribe
 *
 * @param {String}   address
 * @param {Function} handle_fetch Callback to handle subscription result
 * representing for updates
 */

GatewayClient.prototype.unsubscribe = function(address, handle_fetch)
{
    if (this.handler_map["update." + address]) {
        delete this.handler_map["update." + address];
    }
    this.make_request("unsubscribe_address", [address], function(response) {
        handle_fetch(response["error"], response["result"][0]);
    });
}

GatewayClient.prototype.fetch_block_header = function(index, handle_fetch) {
    GatewayClient._check_function(handle_fetch);

    this.make_request("fetch_block_header", [index], function(response) {
        handle_fetch(response["error"], response["result"][0]);
    });
};

GatewayClient.prototype.fetch_block_transaction_hashes = function(
    index, handle_fetch)
{
    GatewayClient._check_function(handle_fetch);

    this.make_request("fetch_block_transaction_hashes", [index],
        function(response) {
            handle_fetch(response["error"], response["result"][0]);
        });
};

GatewayClient.prototype.fetch_spend = function(outpoint, handle_fetch) {
    GatewayClient._check_function(handle_fetch);

    this.make_request("fetch_spend", [outpoint], function(response) {
        handle_fetch(response["error"], response["result"][0]);
    });
};

GatewayClient.prototype.fetch_transaction_index = function(
    tx_hash, handle_fetch)
{
    GatewayClient._check_function(handle_fetch);

    this.make_request("fetch_transaction_index", [tx_hash],
        function(response) {
            result = response["result"];
            handle_fetch(response["error"], result[0], result[1]);
        });
};

GatewayClient.prototype.fetch_block_height = function(blk_hash, handle_fetch)
{
    GatewayClient._check_function(handle_fetch);

    this.make_request("fetch_block_height", [blk_hash], function(response) {
        handle_fetch(response["error"], response["result"][0]);
    });
};

GatewayClient.prototype.broadcast_transaction = function(
    raw_tx, handle_fetch)
{
    GatewayClient._check_function(handle_fetch);

    this.make_request("broadcast_transaction", [raw_tx], function(response) {
        handle_fetch(response["error"], response["result"][0], response["result"][1]);
    });
};

/**
 * Renew
 *
 * @param {String}   address
 * @param {Function} handle_fetch Callback to handle subscription result
 * @param {Function} handle_update Callback to handle the JSON object
 * representing for updates
 */
GatewayClient.prototype.renew = function(address, handle_fetch, handle_update)
{
    var self = this;
    this.make_request("renew_address", [address], function(response) {
        handle_fetch(response["error"], response["result"][0]);
        if (handle_update) {
            self.handler_map["update."+address] = handle_update;
        }
    });
}

/**
 * Chan functionality
 */
GatewayClient.prototype.chan_post = function(section_name, thread_id, data, handle_fetch) {
    GatewayClient._check_function(handle_fetch);

    this.make_request("chan_post", [section_name, thread_id, data], function(response) {
        if (handle_fetch)
            //console.log("raw chan post", response["result"]);
            handle_fetch(response["error"], response["result"]);
    });
};

GatewayClient.prototype.chan_list = function(section_name, handle_fetch) {
    GatewayClient._check_function(handle_fetch);

    this.make_request("chan_list", [section_name], function(response) {
        if (handle_fetch)
            handle_fetch(response["error"], response["result"]);
    });
};

GatewayClient.prototype.chan_get = function(section_name, thread_id, handle_fetch) {
    GatewayClient._check_function(handle_fetch);

    this.make_request("chan_get", [section_name, thread_id], function(response) {
        if (handle_fetch)
            handle_fetch(response["error"], response["result"]);
    });
};

GatewayClient.prototype.chan_subscribe = function(section_name, thread_id, handle_fetch, handle_update) {
    GatewayClient._check_function(handle_fetch);
    var self = this;
    this.make_request("chan_subscribe", [section_name, thread_id], function(response) {
        if (handle_fetch)
            handle_fetch(response["error"], response["result"]);
        if (handle_update) {
            self.handler_map["chan.update." + thread_id] = handle_update;
        }

    });
};
GatewayClient.prototype.chan_unsubscribe = function(section_name, thread_id, handle_fetch, handle_update) {
    GatewayClient._check_function(handle_fetch);
    var self = this;
    this.make_request("chan_unsubscribe", [section_name, thread_id], function(response) {
        if (handle_fetch)
            handle_fetch(response["error"], response["result"]);
        if (self.handler_map["chan.update." + thread_id]) {
            delete self.handler_map["chan.update." + thread_id]
        }
    });
};

/**
 * Ticker functionality
 *
 * @param {String} currency, like USD, EUR...
 * @param {Function} handle_fetch
 */

GatewayClient.prototype.fetch_ticker = function(currency, handle_fetch)
{
    GatewayClient._check_function(handle_fetch);

    this.make_request("fetch_ticker", [currency], function(response) {
        handle_fetch(response["error"], response["result"][0]);
    });
};

/**
 * Make requests to the server
 *
 * @param {String} command
 * @param {Array} params
 * @param {Function} handler
 */
GatewayClient.prototype.make_request = function(command, params, handler) {
    GatewayClient._check_function(handler);

    var id = GatewayClient._random_integer();
    var request = {
        "id": id,
        "command": command,
        "params": params
    };
    var message = JSON.stringify(request);
    this.websocket.send(message);
    this.handler_map[id] = handler;
};

/**
 * Close event handler
 *
 * @param {Object} evt event
 */
GatewayClient.prototype.on_close = function(evt) {
};

/**
 * Error event handler
 *
 * @param {Object} evt event
 *
 * @throws {Object}
 */
GatewayClient.prototype.on_error = function(evt) {
    throw evt;
};

/**
 * After triggering message event, calls to the handler of the petition
 *
 * @param {Object} evt event
 * @private
 */
GatewayClient.prototype._on_message = function(evt) {
    this.on_message(evt)
    response = JSON.parse(evt.data);
    id = response.id;
    // Should be a separate map entirely. This is a hack.
    if (response.type == "update")
        id = "update." + response.address;
    if (response.type == "chan_update")
        id = "chan.update." + response.thread;
    // Prefer flat code over nested.
    if (!this.handler_map[id]) {
        console.log("Handler not found", id);
        return;
    }
    handler = this.handler_map[id];
    handler(response);
};

/**
 * Message event handler
 *
 * @param {Object} evt event
 */
GatewayClient.prototype.on_message = function(evt) {
}

/**
 * (Pseudo-)Random integer generator
 *
 * @return {Number} Random integer
 * @private
 */
GatewayClient._random_integer = function() {
    return Math.floor((Math.random() * 4294967296));
};

/**
 * Checks if param can be executed
 *
 * @param {Function} Function to be checked
 *
 * @throws {String} Parameter is not a function
 * @protected
 */
GatewayClient._check_function = function(func) {
    if (typeof func !== 'function') {
        throw "Parameter is not a function";
    }
};

<|endoftext|>


<commit_before>/*globals define, WebGMEGlobal*/
/*jshint browser: true*/

/**
 * Generated by VisualizerGenerator 0.1.0 from webgme on Wed Mar 16 2016 12:18:29 GMT-0700 (PDT).
 */

define([
    'text!./RootViz.html',
    'text!./DefaultIcon.svg',
    'js/DragDrop/DropTarget',
    'js/DragDrop/DragConstants',
    'common/util/ejs',
    './Templates',
    'js/Utils/GMEConcepts',
    'js/NodePropertyNames',
    'css!./styles/RootVizWidget.css'
], function (
    RootVizHtml,
    DefaultIcon,
    dropTarget,
    DROP_CONSTANTS,
    ejs,
    TEMPLATES,
    GMEConcepts,
    nodePropertyNames) {
    'use strict';

    var RootVizWidget,
        WIDGET_CLASS = 'root-viz';

    RootVizWidget = function (logger, container, client) {
        this._logger = logger.fork('Widget');

        this.$el = container;

	this._client = client;

        this.nodes = {};

        this._initialize();
	this._makeDroppable();

        this._logger.debug('ctor finished');
    };

    RootVizWidget.prototype._initialize = function () {
        // set widget class
        this.$el.addClass(WIDGET_CLASS);
        this.$el.append(RootVizHtml);
	this.$table = this.$el.find('#rootVizTable');
	this._tableSetup = false;
    };

    RootVizWidget.prototype.setupTable = function() {
	var sizeOfElement = 300;
        var width = this.$el.width(),
            height = this.$el.height();
	this._numElementsPerRow = Math.floor(width / sizeOfElement) || 1;
	this.$table.empty();
	this.$table.append('<colgroup>');
	for (var i=0;i<this._numElementsPerRow;i++)
	    this.$table.append('<col width="'+100/this._numElementsPerRow+'%" height="auto">');
	this.$table.append('</colgroup>');
	this._tableSetup = true;

	this._numNodes = 0;
	this._currentRow = 0;
    };

    RootVizWidget.prototype.createNodeEntry = function (desc) {
	var row,
	column,
	panelId;

	if (!this._tableSetup)
	    this.setupTable();

	if ((this._numNodes % this._numElementsPerRow) == 0) {
	    this._currentRow++;
	    this.$table.append('

');
	}

	panelId = desc.id.replace(/\//g,'-');

	row = this.$el.find('#rowClass' + this._currentRow);
	row.append('	');

	this.updateNodeEntry(desc);
	this._numNodes++;
    };

    RootVizWidget.prototype.updateNodeEntry = function(desc) {
	var self = this;
	var column,
	    projectHtml,
	    gmeId,
	    panelId,
	    title,
	    icon,
	    authors,
	    brief,
	    detailed,
	    svg,
	    htmlId,
	    html;

	title = desc.name;
	gmeId = desc.id;
	panelId = gmeId.replace(/\//g,'-');
	icon = desc.icon;
	if (!icon) {
	    icon = DefaultIcon;
	}
	authors = desc.authors;
	brief = desc.brief;
	detailed = desc.detailed;
	projectHtml = ejs.render(TEMPLATES['Project.html.ejs'], {
	    id: panelId,
	    title: title,
	    icon: icon,
	    authors: authors,
	    brief: brief,
	    detailed: detailed
	});

	column = this.$el.find('#colClass' + panelId);
	column.empty();
	column.append(projectHtml);

	var i = document.getElementById("root-viz-menu").style;
	var menuFadeTimeMs = 100;
	function menu(x, y) {
	    i.top = y + "px";
	    i.left = x + "px";
	    i.visibility = "visible";
	    i.opacity = "1";
	}

	function divClicked() {
	    var divHtml = $(this).text();
	    var attribute = $(this).attr('class');
	    var editableText = $("<textarea />");
	    editableText.val(divHtml);
	    editableText.attr('class', attribute);
	    $(this).replaceWith(editableText);
	    editableText.focus();
	    // setup the blur event for this new textarea
	    editableText.blur(editableTextBlurred);
	    event.stopPropagation();
	    event.preventDefault();
	}

	function editableTextBlurred() {
	    var text = $(this).val();
	    var attribute = $(this).attr('class');
	    var viewableText = $("
");
	    viewableText.text(text);
	    viewableText.attr('class', attribute);
	    $(this).replaceWith(viewableText);
	    // setup the click event for this new div
	    viewableText.on('dblclick', divClicked);
	    // save the attribute
	    if (text != "undefined")
		self._client.setAttribute(gmeId, attribute, text);
	}

	// editable authors area
	this.$el.find('#'+panelId+'-authors').on('dblclick', divClicked);
	// editable brief area
	this.$el.find('#'+panelId+'-brief').on('dblclick', divClicked);
	// editable detailed area
	this.$el.find('#'+panelId+'-detailed').on('dblclick', divClicked);

	svg = column.find('svg');
	svg.css('height', '120px');
	svg.css('width', 'auto');

	htmlId = panelId + '-node-panel';
	html = this.$el.find('#' + htmlId);

	html.addClass('panel-info');
	html.on('mouseenter', (event) => {
	    html.addClass('panel-primary');
	    html.removeClass('panel-info');
	});
	html.on('mouseleave', (event) => {
	    html.addClass('panel-info');
	    html.removeClass('panel-primary');
	});
	html.on('click', (event) => {
	    i.opacity = "0";
	    setTimeout(function() {
		i.visibility = "hidden";
	    }, menuFadeTimeMs);

	    this.onNodeSelect(desc.id);
	    //event.stopPropagation();
	    //event.preventDefault();
	});
	html.on('dblclick', (event) => {
	    this.onNodeClick(desc.id);
	    event.stopPropagation();
	    event.preventDefault();
	});
	html.on('contextmenu', (event) => {
	    // handle right click here
	    // make menu with copy option
	    // make menu with delete option
	    var posX = event.clientX;
	    var posY = event.clientY;
	    menu(posX, posY);
	    this.onNodeSelect(desc.id);
	    event.stopPropagation();
	    event.preventDefault();
	});
	// default handlers for the rest of the viz space
	this.$el.on('contextmenu', (event) => {
	    var posX = event.clientX;
	    var posY = event.clientY;
	    menu(posX, posY);
	    event.stopPropagation();
	    event.preventDefault();
	});
	this.$el.on('click', (event) => {
	    i.opacity = "0";
	    setTimeout(function() {
		i.visibility = "hidden";
	    }, menuFadeTimeMs);
	});

	this.nodes[desc.id] = desc;
    };

    RootVizWidget.prototype.onWidgetContainerResize = function (width, height) {
	this.setupTable();
	for (var id in this.nodes) {
            this.addNode(this.nodes[id]);
	}
    };

    // Adding/Removing/Updating items
    var NODE_WHITELIST = {
        Project: true
    };
    RootVizWidget.prototype.addNode = function (desc) {

        if (desc) {
	    var isValid = NODE_WHITELIST[desc.meta];

            if (isValid) {
		//this._nodes.push(desc);
		this.createNodeEntry(desc);
            }
        }
    };

    RootVizWidget.prototype.removeNode = function (gmeId) {
	if (this.nodes[gmeId]) {
            delete this.nodes[gmeId];
	    this.setupTable();
	    for (var id in this.nodes) {
		this.addNode(this.nodes[id]);
	    }
	}
    };

    RootVizWidget.prototype.updateNode = function (desc) {
	this.updateNodeEntry(desc);
    };

    RootVizWidget.prototype._isValidDrop = function (dragInfo) {
	if (!dragInfo)
	    return false;
	var self = this;
        var result = false,
        draggedNodePath,
	nodeObj,
	nodeName,
	metaObj,
	metaName;

        if (dragInfo[DROP_CONSTANTS.DRAG_ITEMS].length === 1) {
            draggedNodePath = dragInfo[DROP_CONSTANTS.DRAG_ITEMS][0];
	    nodeObj = self._client.getNode(draggedNodePath);
	    nodeName = nodeObj.getAttribute('name');
	    metaObj = self._client.getNode(nodeObj.getMetaTypeId());
	    if (metaObj) {
		metaName = metaObj.getAttribute('name');
	    }
            result = metaName && metaName == 'Project';
        }

        return result;
    };

    RootVizWidget.prototype.createProject = function(nodePath) {
	var client = this._client;
	var parentId = '/v', // for our seeds, /v is always 'Projects'
	node = client.getNode(nodePath),
	nodeId = node.getId(),
	baseId = node.getBaseId(),
	baseNode = client.getNode(baseId),
	baseName = baseNode.getAttribute('name');

	if (baseName == 'FCO') { //
	    var childCreationParams = {
		parentId: parentId,  // Should be Projects (/v)
		baseId: nodeId,    // should be META:Project
	    };
	    client.createChild(childCreationParams, 'Creating new Project');
	}
	else if (baseName == 'Project') {
            var params = {parentId: parentId};
	    params[nodeId] = {};
            this._client.startTransaction();
            this._client.copyMoreNodes(params);
            this._client.completeTransaction();
	}
    };

    /* * * * * * * * Visualizer event handlers * * * * * * * */

    RootVizWidget.prototype._makeDroppable = function () {
	var self = this,
	desc;
        self.$el.addClass('drop-area');
        //self._div.append(self.__iconAssignNullPointer);

        dropTarget.makeDroppable(self.$el, {
            over: function (event, dragInfo) {
                if (self._isValidDrop(dragInfo)) {
                    self.$el.addClass('accept-drop');
                } else {
                    self.$el.addClass('reject-drop');
                }
            },
            out: function (/*event, dragInfo*/) {
                self.$el.removeClass('accept-drop reject-drop');
            },
            drop: function (event, dragInfo) {
                if (self._isValidDrop(dragInfo)) {
		    self.createProject(dragInfo[DROP_CONSTANTS.DRAG_ITEMS][0]);
                }
                self.$el.removeClass('accept-drop reject-drop');
            }
        });
    };

    RootVizWidget.prototype.onNodeSelect = function (id) {
	if (id)
	    WebGMEGlobal.State.registerActiveSelection([id]);
    };

    RootVizWidget.prototype.onNodeClick = function (id) {
        // This currently changes the active node to the given id and
        // this is overridden in the controller.
    };

    RootVizWidget.prototype.onBackgroundDblClick = function () {
    };

    /* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
    RootVizWidget.prototype.destroy = function () {
    };

    RootVizWidget.prototype.onActivate = function () {
    };

    RootVizWidget.prototype.onDeactivate = function () {
    };

    return RootVizWidget;
});
<commit_msg>fixed minor bug with menu css.<commit_after>/*globals define, WebGMEGlobal*/
/*jshint browser: true*/

/**
 * Generated by VisualizerGenerator 0.1.0 from webgme on Wed Mar 16 2016 12:18:29 GMT-0700 (PDT).
 */

define([
    'text!./RootViz.html',
    'text!./DefaultIcon.svg',
    'js/DragDrop/DropTarget',
    'js/DragDrop/DragConstants',
    'common/util/ejs',
    './Templates',
    'js/Utils/GMEConcepts',
    'js/NodePropertyNames',
    'css!./styles/RootVizWidget.css'
], function (
    RootVizHtml,
    DefaultIcon,
    dropTarget,
    DROP_CONSTANTS,
    ejs,
    TEMPLATES,
    GMEConcepts,
    nodePropertyNames) {
    'use strict';

    var RootVizWidget,
        WIDGET_CLASS = 'root-viz';

    RootVizWidget = function (logger, container, client) {
        this._logger = logger.fork('Widget');

        this.$el = container;

	this._client = client;

        this.nodes = {};

        this._initialize();
	this._makeDroppable();

        this._logger.debug('ctor finished');
    };

    RootVizWidget.prototype._initialize = function () {
        // set widget class
        this.$el.addClass(WIDGET_CLASS);
        this.$el.append(RootVizHtml);
	this.$table = this.$el.find('#rootVizTable');
	this._tableSetup = false;
    };

    RootVizWidget.prototype.setupTable = function() {
	var sizeOfElement = 300;
        var width = this.$el.width(),
            height = this.$el.height();
	this._numElementsPerRow = Math.floor(width / sizeOfElement) || 1;
	this.$table.empty();
	this.$table.append('<colgroup>');
	for (var i=0;i<this._numElementsPerRow;i++)
	    this.$table.append('<col width="'+100/this._numElementsPerRow+'%" height="auto">');
	this.$table.append('</colgroup>');
	this._tableSetup = true;

	this._numNodes = 0;
	this._currentRow = 0;
    };

    RootVizWidget.prototype.createNodeEntry = function (desc) {
	var row,
	column,
	panelId;

	if (!this._tableSetup)
	    this.setupTable();

	if ((this._numNodes % this._numElementsPerRow) == 0) {
	    this._currentRow++;
	    this.$table.append('

');
	}

	panelId = desc.id.replace(/\//g,'-');

	row = this.$el.find('#rowClass' + this._currentRow);
	row.append('	');

	this.updateNodeEntry(desc);
	this._numNodes++;
    };

    RootVizWidget.prototype.updateNodeEntry = function(desc) {
	var self = this;
	var column,
	    projectHtml,
	    gmeId,
	    panelId,
	    title,
	    icon,
	    authors,
	    brief,
	    detailed,
	    svg,
	    htmlId,
	    html;

	title = desc.name;
	gmeId = desc.id;
	panelId = gmeId.replace(/\//g,'-');
	icon = desc.icon;
	if (!icon) {
	    icon = DefaultIcon;
	}
	authors = desc.authors;
	brief = desc.brief;
	detailed = desc.detailed;
	projectHtml = ejs.render(TEMPLATES['Project.html.ejs'], {
	    id: panelId,
	    title: title,
	    icon: icon,
	    authors: authors,
	    brief: brief,
	    detailed: detailed
	});

	column = this.$el.find('#colClass' + panelId);
	column.empty();
	column.append(projectHtml);

	var i = document.getElementById("root-viz-menu");
	if (i)
	    i = i.style;
	var menuFadeTimeMs = 100;
	function menu(x, y) {
	    if (i) {
		i.top = y + "px";
		i.left = x + "px";
		i.visibility = "visible";
		i.opacity = "1";
	    }
	}

	function divClicked() {
	    var divHtml = $(this).text();
	    var attribute = $(this).attr('class');
	    var editableText = $("<textarea />");
	    editableText.val(divHtml);
	    editableText.attr('class', attribute);
	    $(this).replaceWith(editableText);
	    editableText.focus();
	    // setup the blur event for this new textarea
	    editableText.blur(editableTextBlurred);
	    event.stopPropagation();
	    event.preventDefault();
	}

	function editableTextBlurred() {
	    var text = $(this).val();
	    var attribute = $(this).attr('class');
	    var viewableText = $("
");
	    viewableText.text(text);
	    viewableText.attr('class', attribute);
	    $(this).replaceWith(viewableText);
	    // setup the click event for this new div
	    viewableText.on('dblclick', divClicked);
	    // save the attribute
	    if (text != "undefined")
		self._client.setAttribute(gmeId, attribute, text);
	}

	// editable authors area
	this.$el.find('#'+panelId+'-authors').on('dblclick', divClicked);
	// editable brief area
	this.$el.find('#'+panelId+'-brief').on('dblclick', divClicked);
	// editable detailed area
	this.$el.find('#'+panelId+'-detailed').on('dblclick', divClicked);

	svg = column.find('svg');
	svg.css('height', '120px');
	svg.css('width', 'auto');

	htmlId = panelId + '-node-panel';
	html = this.$el.find('#' + htmlId);

	html.addClass('panel-info');
	html.on('mouseenter', (event) => {
	    html.addClass('panel-primary');
	    html.removeClass('panel-info');
	});
	html.on('mouseleave', (event) => {
	    html.addClass('panel-info');
	    html.removeClass('panel-primary');
	});
	html.on('click', (event) => {
	    i.opacity = "0";
	    setTimeout(function() {
		i.visibility = "hidden";
	    }, menuFadeTimeMs);

	    this.onNodeSelect(desc.id);
	    //event.stopPropagation();
	    //event.preventDefault();
	});
	html.on('dblclick', (event) => {
	    this.onNodeClick(desc.id);
	    event.stopPropagation();
	    event.preventDefault();
	});
	html.on('contextmenu', (event) => {
	    // handle right click here
	    // make menu with copy option
	    // make menu with delete option
	    var posX = event.clientX;
	    var posY = event.clientY;
	    menu(posX, posY);
	    this.onNodeSelect(desc.id);
	    event.stopPropagation();
	    event.preventDefault();
	});
	// default handlers for the rest of the viz space
	this.$el.on('contextmenu', (event) => {
	    var posX = event.clientX;
	    var posY = event.clientY;
	    menu(posX, posY);
	    event.stopPropagation();
	    event.preventDefault();
	});
	this.$el.on('click', (event) => {
	    i.opacity = "0";
	    setTimeout(function() {
		i.visibility = "hidden";
	    }, menuFadeTimeMs);
	});

	this.nodes[desc.id] = desc;
    };

    RootVizWidget.prototype.onWidgetContainerResize = function (width, height) {
	this.setupTable();
	for (var id in this.nodes) {
            this.addNode(this.nodes[id]);
	}
    };

    // Adding/Removing/Updating items
    var NODE_WHITELIST = {
        Project: true
    };
    RootVizWidget.prototype.addNode = function (desc) {

        if (desc) {
	    var isValid = NODE_WHITELIST[desc.meta];

            if (isValid) {
		//this._nodes.push(desc);
		this.createNodeEntry(desc);
            }
        }
    };

    RootVizWidget.prototype.removeNode = function (gmeId) {
	if (this.nodes[gmeId]) {
            delete this.nodes[gmeId];
	    this.setupTable();
	    for (var id in this.nodes) {
		this.addNode(this.nodes[id]);
	    }
	}
    };

    RootVizWidget.prototype.updateNode = function (desc) {
	this.updateNodeEntry(desc);
    };

    RootVizWidget.prototype._isValidDrop = function (dragInfo) {
	if (!dragInfo)
	    return false;
	var self = this;
        var result = false,
        draggedNodePath,
	nodeObj,
	nodeName,
	metaObj,
	metaName;

        if (dragInfo[DROP_CONSTANTS.DRAG_ITEMS].length === 1) {
            draggedNodePath = dragInfo[DROP_CONSTANTS.DRAG_ITEMS][0];
	    nodeObj = self._client.getNode(draggedNodePath);
	    nodeName = nodeObj.getAttribute('name');
	    metaObj = self._client.getNode(nodeObj.getMetaTypeId());
	    if (metaObj) {
		metaName = metaObj.getAttribute('name');
	    }
            result = metaName && metaName == 'Project';
        }

        return result;
    };

    RootVizWidget.prototype.createProject = function(nodePath) {
	var client = this._client;
	var parentId = '/v', // for our seeds, /v is always 'Projects'
	node = client.getNode(nodePath),
	nodeId = node.getId(),
	baseId = node.getBaseId(),
	baseNode = client.getNode(baseId),
	baseName = baseNode.getAttribute('name');

	if (baseName == 'FCO') { //
	    var childCreationParams = {
		parentId: parentId,  // Should be Projects (/v)
		baseId: nodeId,    // should be META:Project
	    };
	    client.createChild(childCreationParams, 'Creating new Project');
	}
	else if (baseName == 'Project') {
            var params = {parentId: parentId};
	    params[nodeId] = {};
            this._client.startTransaction();
            this._client.copyMoreNodes(params);
            this._client.completeTransaction();
	}
    };

    /* * * * * * * * Visualizer event handlers * * * * * * * */

    RootVizWidget.prototype._makeDroppable = function () {
	var self = this,
	desc;
        self.$el.addClass('drop-area');
        //self._div.append(self.__iconAssignNullPointer);

        dropTarget.makeDroppable(self.$el, {
            over: function (event, dragInfo) {
                if (self._isValidDrop(dragInfo)) {
                    self.$el.addClass('accept-drop');
                } else {
                    self.$el.addClass('reject-drop');
                }
            },
            out: function (/*event, dragInfo*/) {
                self.$el.removeClass('accept-drop reject-drop');
            },
            drop: function (event, dragInfo) {
                if (self._isValidDrop(dragInfo)) {
		    self.createProject(dragInfo[DROP_CONSTANTS.DRAG_ITEMS][0]);
                }
                self.$el.removeClass('accept-drop reject-drop');
            }
        });
    };

    RootVizWidget.prototype.onNodeSelect = function (id) {
	if (id)
	    WebGMEGlobal.State.registerActiveSelection([id]);
    };

    RootVizWidget.prototype.onNodeClick = function (id) {
        // This currently changes the active node to the given id and
        // this is overridden in the controller.
    };

    RootVizWidget.prototype.onBackgroundDblClick = function () {
    };

    /* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
    RootVizWidget.prototype.destroy = function () {
    };

    RootVizWidget.prototype.onActivate = function () {
    };

    RootVizWidget.prototype.onDeactivate = function () {
    };

    return RootVizWidget;
});
<|endoftext|>


<commit_before>import React from 'react'
import TestUtils from 'react-addons-test-utils'
import { browserHistory } from 'react-router'
import { expect } from 'chai'
import sinon from 'sinon'

import questions from './../fixtures/questions'
import categories from './../fixtures/categories'

import SurveyPage from '../../../../assets/js/components/ecosystems/SurveyPage'
import LoadingIndicator
  from '../../../../assets/js/components/atoms/LoadingIndicator'

describe('The survey page component', () => {
  let page, state, store, dispatch, push

  beforeEach(() => {
    push = sinon.stub(browserHistory, 'push')
    state = sinon.stub()
    dispatch = sinon.stub()
    store = {
      getState: state,
      subscribe: sinon.stub(),
      dispatch: dispatch
    }
    state.returns({
      survey: {
        selectedSurvey: {
          index: 0
        },
        categories: categories,
        questions: questions,
        responses: [],
        isFetching: false
      }
    })
    page = TestUtils.renderIntoDocument(
      <SurveyPage store={store} />
    ).getWrappedInstance()
  })

  it('will exist', () => {
    expect(page).to.be.ok
  })

  context('under normal circumstances', () => {
    it('will not have any indicators', () => {
      let indicators =
        TestUtils.scryRenderedComponentsWithType(page, LoadingIndicator)
      expect(indicators).to.be.empty
    })
  })

  context('when fetching records', () => {
    context('with no questions', () => {
      beforeEach(() => {
        state.returns({
          survey: {
            questions: [],
            responses: [],
            isFetching: true
          }
        })

        page = TestUtils.renderIntoDocument(
          <SurveyPage store={store} />
        ).getWrappedInstance()
      })

      it('will have an indicator', () => {
        let indicators =
          TestUtils.scryRenderedComponentsWithType(page, LoadingIndicator)
        expect(indicators).to.not.be.empty
      })
    })
  })

  afterEach(() => {
    push.restore()
  })
})
<commit_msg>Update failing tests.<commit_after>import React from 'react'
import TestUtils from 'react-addons-test-utils'
import { browserHistory } from 'react-router'
import { expect } from 'chai'
import sinon from 'sinon'

import questions from './../fixtures/questions'
import categories from './../fixtures/categories'

import SurveyPage from '../../../../assets/js/components/ecosystems/SurveyPage'
import LoadingIndicator
  from '../../../../assets/js/components/atoms/LoadingIndicator'

describe('The survey page component', () => {
  let page, state, store, dispatch, push

  beforeEach(() => {
    push = sinon.stub(browserHistory, 'push')
    state = sinon.stub()
    dispatch = sinon.stub()
    store = {
      getState: state,
      subscribe: sinon.stub(),
      dispatch: dispatch
    }
    state.returns({
      survey: {
        selectedSurvey: {
          index: 0
        },
        categories: categories,
        questions: questions,
        responses: [],
        isFetching: false,
        alerts: []
      }
    })
    page = TestUtils.renderIntoDocument(
      <SurveyPage store={store} />
    ).getWrappedInstance()
  })

  it('will exist', () => {
    expect(page).to.be.ok
  })

  context('under normal circumstances', () => {
    it('will not have any indicators', () => {
      let indicators =
        TestUtils.scryRenderedComponentsWithType(page, LoadingIndicator)
      expect(indicators).to.be.empty
    })
  })

  context('when fetching records', () => {
    context('with no questions', () => {
      beforeEach(() => {
        state.returns({
          survey: {
            questions: [],
            responses: [],
            isFetching: true,
            alerts: []
          }
        })

        page = TestUtils.renderIntoDocument(
          <SurveyPage store={store} />
        ).getWrappedInstance()
      })

      it('will have an indicator', () => {
        let indicators =
          TestUtils.scryRenderedComponentsWithType(page, LoadingIndicator)
        expect(indicators).to.not.be.empty
      })
    })
  })

  afterEach(() => {
    push.restore()
  })
})
<|endoftext|>


<commit_before>require('../support/test_helper');

var assert = require('assert');
var RedisPool = require('redis-mpool');
var TemplateMaps = require('../../lib/cartodb/backends/template_maps.js');
var PgConnection = require(__dirname + '/../../lib/cartodb/backends/pg_connection');
var MapConfigNamedLayersAdapter = require('../../lib/cartodb/models/mapconfig/adapter/mapconfig-named-layers-adapter');

// configure redis pool instance to use in tests
var redisPool = new RedisPool(global.environment.redis);
var pgConnection = new PgConnection(require('cartodb-redis')({ pool: redisPool }));

var templateMaps = new TemplateMaps(redisPool, {
    max_user_templates: global.environment.maxUserTemplates
});

var mapConfigNamedLayersAdapter = new MapConfigNamedLayersAdapter(templateMaps, pgConnection);

var wadusSql = 'select 1 wadusLayer, null::geometry the_geom_webmercator';
var wadusLayer = {
    type: 'cartodb',
    options: {
        sql: wadusSql,
        cartocss: '#layer { marker-fill: black; }',
        cartocss_version: '2.3.0'
    }
};

var wadusTemplateSql = 'select 1 wadusTemplateLayer, null::geometry the_geom_webmercator';
var wadusTemplateLayer = {
    type: 'cartodb',
    options: {
        sql: wadusTemplateSql,
        cartocss: '#layer { marker-fill: <%= color %>; }',
        cartocss_version: '2.3.0'
    }
};

var wadusMapnikSql = 'select 1 wadusMapnikLayer, null::geometry the_geom_webmercator';
var wadusMapnikLayer = {
    type: 'mapnik',
    options: {
        sql: wadusMapnikSql,
        cartocss: '#layer { polygon-fill: <%= polygon_color %>; }',
        cartocss_version: '2.3.0'
    }
};

var username = 'localhost';

var templateName = 'valid_template';
var template = {
    version: '0.0.1',
    name: templateName,
    auth: {
        method: 'open'
    },
    "placeholders": {
        "color": {
            "type": "css_color",
            "default": "#cc3300"
        }
    },
    layergroup: {
        layers: [
            wadusTemplateLayer
        ]
    }
};

var multipleLayersTemplateName = 'multiple_valid_template';
var multipleLayersTemplate = {
    version: '0.0.1',
    name: multipleLayersTemplateName,
    auth: {
        method: 'token',
        valid_tokens: ['valid1', 'valid2']
    },
    "placeholders": {
        "polygon_color": {
            "type": "css_color",
            "default": "green"
        },
        "color": {
            "type": "css_color",
            "default": "red"
        }
    },
    layergroup: {
        layers: [
            wadusMapnikLayer,
            wadusTemplateLayer
        ]
    }
};

describe('named_layers datasources', function() {
    beforeEach(function(done) {
        templateMaps.addTemplate(username, template, function(err) {
            if (err) {
                return done(err);
            }
            templateMaps.addTemplate(username, multipleLayersTemplate, done);
        });
    });

    afterEach(function(done) {
        templateMaps.delTemplate(username, templateName, function(err) {
            if (err) {
                return done(err);
            }
            templateMaps.delTemplate(username, multipleLayersTemplateName, done);
        });
    });

    function makeNamedMapLayerConfig(layers) {
        return {
            version: '1.3.0',
            layers: layers
        };
    }

    var simpleNamedLayer = {
        type: 'named',
        options: {
            name: templateName
        }
    };

    var multipleLayersNamedLayer = {
        type: 'named',
        options: {
            name: multipleLayersTemplateName,
            auth_tokens: ['valid2']
        }
    };

    var testScenarios = [
        {
            desc: 'without datasource for non-named layers',
            config: makeNamedMapLayerConfig([wadusLayer]),
            test: function(err, layers, datasource, done) {
                assert.ok(!err);
                assert.equal(layers.length, 1);

                assert.equal(layers[0].type, 'cartodb');
                assert.equal(layers[0].options.sql, wadusSql);
                assert.equal(datasource.getLayerDatasource(0), undefined);

                done();
            }
        },

        {
            desc: 'with datasource for the named layer but not for the normal',
            config: makeNamedMapLayerConfig([wadusLayer, simpleNamedLayer]),
            test: function(err, layers, datasource, done) {
                assert.ok(!err);
                assert.equal(layers.length, 2);

                assert.equal(layers[0].type, 'cartodb');
                assert.equal(layers[0].options.sql, wadusSql);
                assert.equal(datasource.getLayerDatasource(0), undefined);

                assert.equal(layers[1].type, 'cartodb');
                assert.equal(layers[1].options.sql, wadusTemplateSql);
                var layerDatasource = datasource.getLayerDatasource(1);
                assert.notEqual(layerDatasource, undefined);
                assert.ok(layerDatasource.user);

                done();
            }
        },

        {
            desc: 'with datasource for the multiple layers in the named but not for the normal',
            config: makeNamedMapLayerConfig([wadusLayer, multipleLayersNamedLayer]),
            test: function(err, layers, datasource, done) {
                assert.ok(!err);
                assert.equal(layers.length, 3);

                assert.equal(layers[0].type, 'cartodb');
                assert.equal(layers[0].options.sql, wadusSql);
                assert.equal(datasource.getLayerDatasource(0), undefined);

                assert.equal(layers[1].type, 'mapnik');
                assert.equal(layers[1].options.sql, wadusMapnikSql);
                var layerDatasource = datasource.getLayerDatasource(1);
                assert.notEqual(layerDatasource, undefined);
                assert.ok(layerDatasource.user);

                assert.equal(layers[2].type, 'cartodb');
                assert.equal(layers[2].options.sql, wadusTemplateSql);
                layerDatasource = datasource.getLayerDatasource(2);
                assert.notEqual(layerDatasource, undefined);
                assert.ok(layerDatasource.user);

                done();
            }
        },

        {
            desc: 'all with datasource because all are named',
            config: makeNamedMapLayerConfig([multipleLayersNamedLayer, simpleNamedLayer]),
            test: function(err, layers, datasource, done) {
                assert.ok(!err);
                assert.equal(layers.length, 3);

                assert.equal(layers[0].type, 'mapnik');
                assert.equal(layers[0].options.sql, wadusMapnikSql);
                var layerDatasource = datasource.getLayerDatasource(0);
                assert.notEqual(layerDatasource, undefined);
                assert.ok(layerDatasource.user);

                assert.equal(layers[1].type, 'cartodb');
                assert.equal(layers[1].options.sql, wadusTemplateSql);
                layerDatasource = datasource.getLayerDatasource(1);
                assert.notEqual(layerDatasource, undefined);
                assert.ok(layerDatasource.user);

                assert.equal(layers[2].type, 'cartodb');
                assert.equal(layers[2].options.sql, wadusTemplateSql);
                layerDatasource = datasource.getLayerDatasource(2);
                assert.notEqual(layerDatasource, undefined);
                assert.ok(layerDatasource.user);

                done();
            }
        },

        {
            desc: 'with a mix of datasource and no datasource depending if layers are named or not',
            config: makeNamedMapLayerConfig([
                simpleNamedLayer,
                multipleLayersNamedLayer,
                wadusLayer,
                simpleNamedLayer,
                wadusLayer,
                multipleLayersNamedLayer
            ]),
            test: function(err, layers, datasource, done) {

                assert.ok(!err);
                assert.equal(layers.length, 8);

                assert.equal(layers[0].type, 'cartodb');
                assert.equal(layers[0].options.sql, wadusTemplateSql);
                var layerDatasource = datasource.getLayerDatasource(0);
                assert.notEqual(layerDatasource, undefined);
                assert.ok(layerDatasource.user);

                assert.equal(layers[1].type, 'mapnik');
                assert.equal(layers[1].options.sql, wadusMapnikSql);
                layerDatasource = datasource.getLayerDatasource(1);
                assert.notEqual(layerDatasource, undefined);
                assert.ok(layerDatasource.user);

                assert.equal(layers[2].type, 'cartodb');
                assert.equal(layers[2].options.sql, wadusTemplateSql);
                layerDatasource = datasource.getLayerDatasource(2);
                assert.notEqual(layerDatasource, undefined);
                assert.ok(layerDatasource.user);

                assert.equal(layers[3].type, 'cartodb');
                assert.equal(layers[3].options.sql, wadusSql);
                assert.equal(datasource.getLayerDatasource(3), undefined);

                assert.equal(layers[4].type, 'cartodb');
                assert.equal(layers[4].options.sql, wadusTemplateSql);
                layerDatasource = datasource.getLayerDatasource(4);
                assert.notEqual(layerDatasource, undefined);
                assert.ok(layerDatasource.user);

                assert.equal(layers[5].type, 'cartodb');
                assert.equal(layers[5].options.sql, wadusSql);
                assert.equal(datasource.getLayerDatasource(5), undefined);

                assert.equal(layers[6].type, 'mapnik');
                assert.equal(layers[6].options.sql, wadusMapnikSql);
                layerDatasource = datasource.getLayerDatasource(6);
                assert.notEqual(layerDatasource, undefined);
                assert.ok(layerDatasource.user);

                assert.equal(layers[7].type, 'cartodb');
                assert.equal(layers[7].options.sql, wadusTemplateSql);
                layerDatasource = datasource.getLayerDatasource(7);
                assert.notEqual(layerDatasource, undefined);
                assert.ok(layerDatasource.user);

                done();
            }
        }
    ];

    testScenarios.forEach(function(testScenario) {
        it('should return a list of layers ' + testScenario.desc, function(done) {
            var params = {};
            var context = {};
            mapConfigNamedLayersAdapter.getMapConfig(username, testScenario.config, params, context,
                function(err, mapConfig) {
                    testScenario.test(err, mapConfig.layers, context.datasource, done);
                }
            );
        });
    });
});
<commit_msg>Fix assertions, now MapCofig.getLayer() return {} if layer not found<commit_after>require('../support/test_helper');

var assert = require('assert');
var RedisPool = require('redis-mpool');
var TemplateMaps = require('../../lib/cartodb/backends/template_maps.js');
var PgConnection = require(__dirname + '/../../lib/cartodb/backends/pg_connection');
var MapConfigNamedLayersAdapter = require('../../lib/cartodb/models/mapconfig/adapter/mapconfig-named-layers-adapter');

// configure redis pool instance to use in tests
var redisPool = new RedisPool(global.environment.redis);
var pgConnection = new PgConnection(require('cartodb-redis')({ pool: redisPool }));

var templateMaps = new TemplateMaps(redisPool, {
    max_user_templates: global.environment.maxUserTemplates
});

var mapConfigNamedLayersAdapter = new MapConfigNamedLayersAdapter(templateMaps, pgConnection);

var wadusSql = 'select 1 wadusLayer, null::geometry the_geom_webmercator';
var wadusLayer = {
    type: 'cartodb',
    options: {
        sql: wadusSql,
        cartocss: '#layer { marker-fill: black; }',
        cartocss_version: '2.3.0'
    }
};

var wadusTemplateSql = 'select 1 wadusTemplateLayer, null::geometry the_geom_webmercator';
var wadusTemplateLayer = {
    type: 'cartodb',
    options: {
        sql: wadusTemplateSql,
        cartocss: '#layer { marker-fill: <%= color %>; }',
        cartocss_version: '2.3.0'
    }
};

var wadusMapnikSql = 'select 1 wadusMapnikLayer, null::geometry the_geom_webmercator';
var wadusMapnikLayer = {
    type: 'mapnik',
    options: {
        sql: wadusMapnikSql,
        cartocss: '#layer { polygon-fill: <%= polygon_color %>; }',
        cartocss_version: '2.3.0'
    }
};

var username = 'localhost';

var templateName = 'valid_template';
var template = {
    version: '0.0.1',
    name: templateName,
    auth: {
        method: 'open'
    },
    "placeholders": {
        "color": {
            "type": "css_color",
            "default": "#cc3300"
        }
    },
    layergroup: {
        layers: [
            wadusTemplateLayer
        ]
    }
};

var multipleLayersTemplateName = 'multiple_valid_template';
var multipleLayersTemplate = {
    version: '0.0.1',
    name: multipleLayersTemplateName,
    auth: {
        method: 'token',
        valid_tokens: ['valid1', 'valid2']
    },
    "placeholders": {
        "polygon_color": {
            "type": "css_color",
            "default": "green"
        },
        "color": {
            "type": "css_color",
            "default": "red"
        }
    },
    layergroup: {
        layers: [
            wadusMapnikLayer,
            wadusTemplateLayer
        ]
    }
};

describe('named_layers datasources', function() {
    beforeEach(function(done) {
        templateMaps.addTemplate(username, template, function(err) {
            if (err) {
                return done(err);
            }
            templateMaps.addTemplate(username, multipleLayersTemplate, done);
        });
    });

    afterEach(function(done) {
        templateMaps.delTemplate(username, templateName, function(err) {
            if (err) {
                return done(err);
            }
            templateMaps.delTemplate(username, multipleLayersTemplateName, done);
        });
    });

    function makeNamedMapLayerConfig(layers) {
        return {
            version: '1.3.0',
            layers: layers
        };
    }

    var simpleNamedLayer = {
        type: 'named',
        options: {
            name: templateName
        }
    };

    var multipleLayersNamedLayer = {
        type: 'named',
        options: {
            name: multipleLayersTemplateName,
            auth_tokens: ['valid2']
        }
    };

    var testScenarios = [
        {
            desc: 'without datasource for non-named layers',
            config: makeNamedMapLayerConfig([wadusLayer]),
            test: function(err, layers, datasource, done) {
                assert.ok(!err);
                assert.equal(layers.length, 1);

                assert.equal(layers[0].type, 'cartodb');
                assert.equal(layers[0].options.sql, wadusSql);
                assert.deepEqual(datasource.getLayerDatasource(0), {});

                done();
            }
        },

        {
            desc: 'with datasource for the named layer but not for the normal',
            config: makeNamedMapLayerConfig([wadusLayer, simpleNamedLayer]),
            test: function(err, layers, datasource, done) {
                assert.ok(!err);
                assert.equal(layers.length, 2);

                assert.equal(layers[0].type, 'cartodb');
                assert.equal(layers[0].options.sql, wadusSql);
                assert.deepEqual(datasource.getLayerDatasource(0), {});

                assert.equal(layers[1].type, 'cartodb');
                assert.equal(layers[1].options.sql, wadusTemplateSql);
                var layerDatasource = datasource.getLayerDatasource(1);
                assert.notEqual(layerDatasource, undefined);
                assert.ok(layerDatasource.user);

                done();
            }
        },

        {
            desc: 'with datasource for the multiple layers in the named but not for the normal',
            config: makeNamedMapLayerConfig([wadusLayer, multipleLayersNamedLayer]),
            test: function(err, layers, datasource, done) {
                assert.ok(!err);
                assert.equal(layers.length, 3);

                assert.equal(layers[0].type, 'cartodb');
                assert.equal(layers[0].options.sql, wadusSql);
                assert.deepEqual(datasource.getLayerDatasource(0), {});

                assert.equal(layers[1].type, 'mapnik');
                assert.equal(layers[1].options.sql, wadusMapnikSql);
                var layerDatasource = datasource.getLayerDatasource(1);
                assert.notEqual(layerDatasource, undefined);
                assert.ok(layerDatasource.user);

                assert.equal(layers[2].type, 'cartodb');
                assert.equal(layers[2].options.sql, wadusTemplateSql);
                layerDatasource = datasource.getLayerDatasource(2);
                assert.notEqual(layerDatasource, undefined);
                assert.ok(layerDatasource.user);

                done();
            }
        },

        {
            desc: 'all with datasource because all are named',
            config: makeNamedMapLayerConfig([multipleLayersNamedLayer, simpleNamedLayer]),
            test: function(err, layers, datasource, done) {
                assert.ok(!err);
                assert.equal(layers.length, 3);

                assert.equal(layers[0].type, 'mapnik');
                assert.equal(layers[0].options.sql, wadusMapnikSql);
                var layerDatasource = datasource.getLayerDatasource(0);
                assert.notEqual(layerDatasource, undefined);
                assert.ok(layerDatasource.user);

                assert.equal(layers[1].type, 'cartodb');
                assert.equal(layers[1].options.sql, wadusTemplateSql);
                layerDatasource = datasource.getLayerDatasource(1);
                assert.notEqual(layerDatasource, undefined);
                assert.ok(layerDatasource.user);

                assert.equal(layers[2].type, 'cartodb');
                assert.equal(layers[2].options.sql, wadusTemplateSql);
                layerDatasource = datasource.getLayerDatasource(2);
                assert.notEqual(layerDatasource, undefined);
                assert.ok(layerDatasource.user);

                done();
            }
        },

        {
            desc: 'with a mix of datasource and no datasource depending if layers are named or not',
            config: makeNamedMapLayerConfig([
                simpleNamedLayer,
                multipleLayersNamedLayer,
                wadusLayer,
                simpleNamedLayer,
                wadusLayer,
                multipleLayersNamedLayer
            ]),
            test: function(err, layers, datasource, done) {

                assert.ok(!err);
                assert.equal(layers.length, 8);

                assert.equal(layers[0].type, 'cartodb');
                assert.equal(layers[0].options.sql, wadusTemplateSql);
                var layerDatasource = datasource.getLayerDatasource(0);
                assert.notEqual(layerDatasource, undefined);
                assert.ok(layerDatasource.user);

                assert.equal(layers[1].type, 'mapnik');
                assert.equal(layers[1].options.sql, wadusMapnikSql);
                layerDatasource = datasource.getLayerDatasource(1);
                assert.notEqual(layerDatasource, undefined);
                assert.ok(layerDatasource.user);

                assert.equal(layers[2].type, 'cartodb');
                assert.equal(layers[2].options.sql, wadusTemplateSql);
                layerDatasource = datasource.getLayerDatasource(2);
                assert.notEqual(layerDatasource, undefined);
                assert.ok(layerDatasource.user);

                assert.equal(layers[3].type, 'cartodb');
                assert.equal(layers[3].options.sql, wadusSql);
                assert.deepEqual(datasource.getLayerDatasource(3), {});

                assert.equal(layers[4].type, 'cartodb');
                assert.equal(layers[4].options.sql, wadusTemplateSql);
                layerDatasource = datasource.getLayerDatasource(4);
                assert.notEqual(layerDatasource, undefined);
                assert.ok(layerDatasource.user);

                assert.equal(layers[5].type, 'cartodb');
                assert.equal(layers[5].options.sql, wadusSql);
                assert.deepEqual(datasource.getLayerDatasource(5), {});

                assert.equal(layers[6].type, 'mapnik');
                assert.equal(layers[6].options.sql, wadusMapnikSql);
                layerDatasource = datasource.getLayerDatasource(6);
                assert.notEqual(layerDatasource, undefined);
                assert.ok(layerDatasource.user);

                assert.equal(layers[7].type, 'cartodb');
                assert.equal(layers[7].options.sql, wadusTemplateSql);
                layerDatasource = datasource.getLayerDatasource(7);
                assert.notEqual(layerDatasource, undefined);
                assert.ok(layerDatasource.user);

                done();
            }
        }
    ];

    testScenarios.forEach(function(testScenario) {
        it('should return a list of layers ' + testScenario.desc, function(done) {
            var params = {};
            var context = {};
            mapConfigNamedLayersAdapter.getMapConfig(username, testScenario.config, params, context,
                function(err, mapConfig) {
                    assert.ifError(err);
                    testScenario.test(err, mapConfig.layers, context.datasource, done);
                }
            );
        });
    });
});
<|endoftext|>


<commit_before>ZBase.registerView((function() {
  var Overview = {};
  var Editor = {};

  Editor.render = function() {
    var viewport = document.getElementById("zbase_viewport");
    var page = ZBase.getTemplate(
      "sql_editor", "zbase_sql_editor_main_tpl");
    ZBase.util.install_link_handlers(page);

    viewport.innerHTML = "";
    viewport.appendChild(page);

    document.querySelector(".zbase_sql_editor_pane .zbase_loader")
      .classList.add("hidden");
  };

  Overview.render = function() {
    var viewport = document.getElementById("zbase_viewport");
    var page = ZBase.getTemplate(
      "sql_editor", "zbase_sql_editor_overview_main_tpl");
    ZBase.util.install_link_handlers(page);

    viewport.innerHTML = "";
    viewport.appendChild(page);

    Overview.load();
    Overview.handleNewQueryButton();
  };

  Overview.handleNewQueryButton = function() {
    document.querySelector(
      ".zbase_sql_editor button[data-action='new-query']")
      .addEventListener("click", function() {
        ZBase.util.httpPost("/analytics/api/v1/documents/sql_queries", "", function(r) {
          var response = JSON.parse(r.response);
          window.location.href = "/a/sql/" + response.uuid;
        });
      });
  };

  Overview.renderTable = function(documents) {
    var tbody = document.querySelector(".zbase_sql_editor_overview tbody");
    documents.forEach(function(doc) {
      var url = "/a/sql/" + doc.uuid;
      var tr = document.createElement("tr");
      tr.innerHTML = "" + doc.name + "	" +
        "" + doc.type + "	—	";
      tbody.appendChild(tr);

      tr.addEventListener("click", function() {
        window.location.href = url;
      });
    });

    document.querySelector(".zbase_sql_editor_overview .zbase_loader")
      .classList.add("hidden");
  };

  Overview.load = function() {
    ZBase.util.httpGet("/analytics/api/v1/documents", function(r) {
      if (r.status == 200) {
        var documents = JSON.parse(r.response).documents;
        Overview.renderTable(documents);
      } else {
        //TODO render error message
      }
    });
  };

  var render = function(path) {
    var path_parts = path.split("/");
    var view;
    // render view
    if (path_parts.length == 4 && path_parts[3].length > 0) {
      Editor.render();
    } else {
      Overview.render();
    }
  };

  return {
    name: "sql_editor",

    loadView: function(params) {
      render(params.path);
    },
    unloadView: function() {
    },
    handleNavigationChange: function(url){
      render(url);
    }
  };

})());
<commit_msg>validateAndFetchDocument<commit_after>ZBase.registerView((function() {
  var Overview = {};
  var Editor = {};
  var path_parts;

  Editor.render = function() {
    var viewport = document.getElementById("zbase_viewport");
    var page = ZBase.getTemplate(
      "sql_editor", "zbase_sql_editor_main_tpl");
    ZBase.util.install_link_handlers(page);

    viewport.innerHTML = "";
    viewport.appendChild(page);

    Editor.validateAndFetchDocument();
    Editor.doc_sync = new DocSync(function() {
      return "content=" + encodeURIComponent(document.querySelector("[data-content='query_content']").getValue()) +
      "&name=" + encodeURIComponent(document.querySelector("[data-content='query_name']").getValue())
      },
      "/analytics/api/v1/sql_queries/" + Editor.doc_id
    );

    document.querySelector(".zbase_sql_editor_pane .zbase_loader")
      .classList.add("hidden");
  };

  Editor.validateAndFetchDocument = function() {
    Editor.doc_id = path_parts[3];
    if (!/^[A-Za-z0-9]+$/.test(Editor.doc_id)) {
      //TODO redirect and display message
      alert("invalid docid");
      return;
    }

    ZBase.util.httpGet("/analytics/api/v1/documents/sql_queries/" + Editor.doc_id, function(r) {
      if (r.status == 200) {
        Editor.doc = JSON.parse(r.response);

        console.log(Editor.doc);
      }
    });
  };

  Overview.render = function() {
    var viewport = document.getElementById("zbase_viewport");
    var page = ZBase.getTemplate(
      "sql_editor", "zbase_sql_editor_overview_main_tpl");
    ZBase.util.install_link_handlers(page);

    viewport.innerHTML = "";
    viewport.appendChild(page);

    Overview.load();
    Overview.handleNewQueryButton();
  };

  Overview.handleNewQueryButton = function() {
    document.querySelector(
      ".zbase_sql_editor button[data-action='new-query']")
      .addEventListener("click", function() {
        ZBase.util.httpPost("/analytics/api/v1/documents/sql_queries", "", function(r) {
          var response = JSON.parse(r.response);
          window.location.href = "/a/sql/" + response.uuid;
        });
      });
  };

  Overview.renderTable = function(documents) {
    var tbody = document.querySelector(".zbase_sql_editor_overview tbody");
    documents.forEach(function(doc) {
      var url = "/a/sql/" + doc.uuid;
      var tr = document.createElement("tr");
      tr.innerHTML = "" + doc.name + "	" +
        "" + doc.type + "	—	";
      tbody.appendChild(tr);

      tr.addEventListener("click", function() {
        window.location.href = url;
      });
    });

    document.querySelector(".zbase_sql_editor_overview .zbase_loader")
      .classList.add("hidden");
  };

  Overview.load = function() {
    ZBase.util.httpGet("/analytics/api/v1/documents", function(r) {
      if (r.status == 200) {
        var documents = JSON.parse(r.response).documents;
        Overview.renderTable(documents);
      } else {
        //TODO render error message
      }
    });
  };

  var render = function(path) {
    path_parts = path.split("/");
    var view;
    // render view
    if (path_parts.length == 4 && path_parts[3].length > 0) {
      Editor.render();
    } else {
      Overview.render();
    }
  };

  return {
    name: "sql_editor",

    loadView: function(params) {
      render(params.path);
    },
    unloadView: function() {
    },
    handleNavigationChange: function(url){
      render(url);
    }
  };

})());
<|endoftext|>


<commit_before>ZBase.registerView((function() {
  var Overview = {};
  var Editor = {};
  var path_parts;

  function renderTableList(source_handler, pane) {
    var ul = pane.querySelector(".zbase_sql_editor_table_list");
    var source_id = "tables";
    var source = source_handler.get(
      source_id,
      "/api/v1/sql_stream?query=" + encodeURIComponent("SHOW TABLES;"));

    source.addEventListener('result', function(e) {
      source_handler.close(source_id);

      var data = JSON.parse(e.data);
      data.results[0].rows.forEach(function(table) {
        var li = document.createElement("li");
        li.innerHTML = table[0];
        ul.appendChild(li);
        li.addEventListener('click', function() {
          renderTableDescriptionModal(source_handler, table[0]);
        }, false);
      });
      pane.querySelector(".sidebar_section .zbase_loader").classList.add("hidden");
      ul.style.display = "block";
    });
  };

  function renderTableDescriptionModal(source_handler, table) {
    var modal = document.querySelector(".zbase_sql_editor_modal.table_descr");
    var loader = modal.querySelector(".zbase_loader");
    var source_id = "table_descr";
    var source = source_handler.get(
      source_id,
      "/api/v1/sql_stream?query=" + encodeURIComponent("DESCRIBE '" + table + "';"));

    modal.querySelector(".zbase_modal_header").innerHTML = table;
    loader.classList.remove("hidden");
    modal.show();

    source.addEventListener('result', function(e) {
      source_handler.close(source_id);
      var result = JSON.parse(e.data).results[0];
      var header = modal.querySelector("thead tr");
      var body = modal.querySelector("tbody");

      header.innerHTML = "";
      result.columns.forEach(function(column) {
        header.innerHTML += "" + column + "</th";
      });

      body.innerHTML = "";
      result.rows.forEach(function(row) {
        var html = "
"
        row.forEach(function(cell) {
          html += "" + cell + "	";
        });
        html += "
";
        body.innerHTML += html;
      });

      loader.classList.add("hidden");
      modal.querySelector(".error_message").classList.add("hidden");
      modal.querySelector(".zbase_table").classList.remove("hidden");
    });

    source.addEventListener("error", function(e) {
      source_handler.close(source_id);
      var error_message = modal.querySelector(".error_message");
      try {
        error_message.innerHTML = JSON.parse(e.data).error;
      } catch (err) {
        error_message.innerHTML = e.data;
      }

      loader.classList.add("hidden");
      modal.querySelector(".zbase_table").classList.add("hidden");
      error_message.classList.remove("hidden");
    });
  };

  /**
    * SQL Editor
    */
  Editor.render = function() {
    var viewport = document.getElementById("zbase_viewport");
    var page = ZBase.getTemplate(
      "sql_editor", "zbase_sql_editor_main_tpl");
    ZBase.util.install_link_handlers(page);

    viewport.innerHTML = "";
    viewport.appendChild(page);

    Editor.validateAndFetchDocument();

    Editor.doc_sync = new DocSync(function() {
      return "content=" + encodeURIComponent(document.querySelector(".zbase_sql_editor_pane fn-codeeditor").getValue()) +
      "&name=" + encodeURIComponent(document.querySelector(".zbase_sql_editor_pane input[name='doc_name']").value)
      },
      "/api/v1/documents/sql_queries/" + Editor.doc_id,
      document.querySelector(".zbase_sql_editor_pane .zbase_sql_editor_infobar")
    );

    Editor.source_handler = new EventSourceHandler();
    renderTableList(
      Editor.source_handler,
      document.querySelector(".zbase_sql_editor_pane"));
  };

  Editor.validateAndFetchDocument = function() {
    Editor.doc_id = path_parts[3];
    // invalid docid
    if (!/^[A-Za-z0-9]+$/.test(Editor.doc_id)) {
      //TODO redirect and display message
      alert("invalid docid");
      return;
    }

    // fetch document
    ZBase.util.httpGet("/api/v1/documents/sql_queries/" + Editor.doc_id, function(r) {
      if (r.status == 200) {
        var doc = JSON.parse(r.response);
        Editor.handleNameEditing(doc.name);
        Editor.setQueryContent(doc.sql_query);
        Editor.observeQueryExecution();

        document.querySelector(".zbase_sql_editor_pane .zbase_loader.fullscreen")
          .classList.add("hidden");
      }
    });
  };

  Editor.setQueryContent = function(query) {
    document.querySelector(".zbase_sql_editor_pane fn-codeeditor").setValue(query);
    if (query != "-- SELECT ... FROM ...;" && query.length > 0) {
      Editor.executeQuery(query);
    }
  };

  Editor.observeQueryExecution = function() {
    var editor = document.querySelector(".zbase_sql_editor_pane fn-codeeditor");
    var exec_btn = document.querySelector(
      ".zbase_sql_editor_pane button[data-action='execute-query']");

    /*document.querySelector("fn-tooltip[data-target='query_exec_btn']").init(
      exec_btn);*/

    exec_btn.addEventListener('click', function() {
      Editor.executeQuery(editor.getValue());
    }, false);

    var cmd_pressed = false;
    editor.addEventListener('keydown', function(e) {
      if (e.keyCode == 17 || e.keyCode == 91) {
        cmd_pressed = true;
      }
    }, false);

    editor.addEventListener('keyup', function(e) {
      if (e.keyCode == 17 || e.keyCode == 91) {
        cmd_pressed = false;
      }
    }, false);

    editor.addEventListener('keydown', function(e) {
      if (e.keyCode == 13 && cmd_pressed) {
        e.preventDefault();
        Editor.executeQuery(editor.getValue());
      }
    }, false);

    var value = editor.getValue();
    editor.addEventListener('keyup', function() {
      var new_value = editor.getValue();
      if (value == new_value) {return;}
      value = new_value;
      Editor.doc_sync.cur_version++;
      Editor.doc_sync.documentChanged("content_changed");
    }, false);

  };

  Editor.executeQuery = function(query) {
    var id = "query";

    Editor.setResultVisibility("loading");
    Editor.source_handler.close(id);
    var source = Editor.source_handler.get(
      id,
      "/api/v1/sql_stream?query=" + encodeURIComponent(query));

    source.addEventListener('result', function(e) {
      var end = (new Date()).getTime();
      Editor.source_handler.close(id);
      var data = JSON.parse(e.data);
      Editor.renderResults(data.results);
      Editor.setResultVisibility("result");
    });

    source.addEventListener('error', function(e) {
      Editor.source_handler.close(id);
      try {
        document.querySelector('.zbase_sql_editor_pane .error_text').innerHTML = JSON.parse(e.data).error;
      } catch (e) {
        document.querySelector('.zbase_sql_editor_pane .error_text').innerHTML = e.data;
      }
      Editor.setResultVisibility("error");
    });

  };

  Editor.setResultVisibility = function(state) {
    switch (state) {
      case "loading":
        document.querySelector('.zbase_sql_editor_result_pane')
          .classList.add("hidden");
        document.querySelector('.zbase_sql_editor_pane .error_message')
          .classList.add("hidden");
        document.querySelector(".zbase_sql_result_loader")
          .classList.remove("hidden");
        return;

      case "error":
        document.querySelector('.zbase_sql_editor_pane .error_message')
          .classList.remove("hidden");
        document.querySelector(".zbase_sql_result_loader")
          .classList.add("hidden");
        return;

      case "result":
        document.querySelector('.zbase_sql_editor_result_pane')
          .classList.remove("hidden");
        document.querySelector(".zbase_sql_result_loader")
          .classList.add("hidden");
      return;

      default:
        break;
    }
  };

  Editor.renderResultTable = function(rows, columns) {
    var table = document.createElement("table");
    table.className = 'zbase_table';

    innerHTML = "

";
    columns.forEach(function(column) {
      innerHTML += "" + column + "	";
    });

    innerHTML += "

";

    rows.forEach(function(row) {
      innerHTML += "
";
      row.forEach(function(cell) {
        innerHTML += "" + cell + "	";
      });
      innerHTML += "
";
    });

    innerHTML += "
";
    table.innerHTML = innerHTML;
    return table;
  };

  Editor.renderResultChart = function(svg) {
    var elem = document.createElement("div");
    elem.className = "zbase_sql_chart";
    elem.innerHTML = svg;
    return elem;
  };

  Editor.renderResultBar = function(index, multiple_results) {
    var bar = document.createElement("div");
    bar.className = "zbase_result_pane_bar";
    bar.setAttribute('data-active', 'active');
    bar.innerHTML =
      "Result " + (index + 1) + "";

    if (multiple_results) {
      bar.className += " clickable";
      bar.addEventListener('click', function() {
        if (this.hasAttribute('data-active')) {
          this.removeAttribute('data-active');
        } else {
          this.setAttribute('data-active', 'active');
        }
      }, false);
    }

    return bar;
  };

  Editor.renderResults = function(results) {
    var result_pane = document.querySelector(
      ".zbase_sql_editor_pane .zbase_sql_editor_result_pane");

    result_pane.innerHTML = "";
    for (var i = 0; i < results.length; i++) {
      result_pane.appendChild(Editor.renderResultBar(i, results.length > 1));
      var elem;
      switch (results[i].type) {
        case "chart":
          elem = Editor.renderResultChart(results[i].svg);
          break;
        case "table":
          elem = Editor.renderResultTable(results[i].rows, results[i].columns)
          break;
      }
      result_pane.appendChild(elem);
    }
  };

  Editor.handleNameEditing = function(doc_name) {
    var name_elem = document.querySelector(".zbase_sql_editor_pane .pagetitle");
    var modal = document.querySelector(
      ".zbase_sql_editor_pane fn-modal.rename_query");
    var input = modal.querySelector("input");
    var submit_btn = modal.querySelector("button[data-action='submit']");
    name_elem.innerHTML = doc_name;

    name_elem.addEventListener("click", function() {
      input.value = name_elem.innerText;
      modal.show();
      input.focus();
    }, false);

    input.addEventListener('keyup', function() {
      if (input.value.length == 0) {
        submit_btn.classList.add('disabled');
      } else if (submit_btn.classList.contains('disabled')) {
        submit_btn.classList.remove("disabled");
      }
    }, false);

    submit_btn.addEventListener('click', function() {
      var name = input.value;
      if (name.length == 0) {
        return;
      }
      name_elem.innerHTML = name;
      modal.close();
      Editor.doc_sync.cur_version++;
      Editor.doc_sync.documentChanged("content_changed");
    }, false);
  };

  /**
    * SQL Editor Overview
    */
  Overview.render = function() {
    var viewport = document.getElementById("zbase_viewport");
    var page = ZBase.getTemplate(
      "sql_editor", "zbase_sql_editor_overview_main_tpl");
    ZBase.util.install_link_handlers(page);

    viewport.innerHTML = "";
    viewport.appendChild(page);

    Overview.source_handler = new EventSourceHandler();
    Overview.load();
    Overview.handleNewQueryButton();
    renderTableList(
      Overview.source_handler,
      document.querySelector(".zbase_sql_editor_overview"));
  };

  Overview.handleNewQueryButton = function() {
    document.querySelector(
      ".zbase_sql_editor button[data-action='new-query']")
      .addEventListener("click", function() {
        ZBase.util.httpPost("/api/v1/documents/sql_queries", "", function(r) {
          var response = JSON.parse(r.response);
          window.location.href = "/a/sql/" + response.uuid;
        });
      });
  };

  Overview.renderTable = function(documents) {
    var tbody = document.querySelector(".zbase_sql_editor_overview tbody");
    documents.forEach(function(doc) {
      var url = "/a/sql/" + doc.uuid;
      var tr = document.createElement("tr");
      tr.innerHTML = "" + doc.name + "	" +
        "" + doc.type + "	—	";
      tbody.appendChild(tr);

      tr.addEventListener("click", function() {
        window.location.href = url;
      });
    });

    document.querySelector(".zbase_sql_editor_overview .zbase_loader.fullscreen")
      .classList.add("hidden");
  };

  Overview.load = function() {
    ZBase.util.httpGet("/api/v1/documents", function(r) {
      if (r.status == 200) {
        var documents = JSON.parse(r.response).documents;
        Overview.renderTable(documents);
      } else {
        //TODO render error message
      }
    });
  };

  var render = function(path) {
    path_parts = path.split("/");
    var view;
    // render view
    if (path_parts.length == 4 && path_parts[3].length > 0) {
      Editor.render();
    } else {
      Overview.render();
    }
  };

  return {
    name: "sql_editor",

    loadView: function(params) {
      render(params.path);
    },
    unloadView: function() {
      if (Editor.source_handler) {
        Editor.source_handler.closeAll();
      } else if (Overview.source_handler) {
        Overview.source_handler.closeAll();
      }
    },
    handleNavigationChange: function(url){
      render(url);
    }
  };

})());
<commit_msg>delete dead code<commit_after><|endoftext|>