<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.
(function(cloudStack) {
  cloudStack.sections.domains = {
    title: 'label.menu.domains',
    id: 'domains',

    // Domain tree
    treeView: {
      // Details
      detailView: {
        name: 'Domain details',
        viewAll: {
          label: 'label.accounts',
          path: 'accounts'
        },

        // Detail actions
        actions: {
          'delete': {
            label: 'label.action.delete.domain',
            messages: {
              notification: function(args) {
                return 'label.action.delete.domain';
              }
            },

            createForm: {
              title: 'label.action.delete.domain',
              desc: 'message.action.delete.domain',
              createLabel: 'label.delete',
              preFilter: function(args) {
                if(isAdmin()) {
                  args.$form.find('.form-item[rel=isForced]').css('display', 'inline-block');
                }
              },
              fields: {
                isForced: {
                  label: 'force.delete',
                  isBoolean: true,
                  isHidden: true
                }
              }
            },

            action: function(args) {
              var array1 = [];
              if(args.$form.find('.form-item[rel=isForced]').css("display") != "none") //uncomment after Brian fix it to include $form in args
                array1.push("&cleanup=" + (args.data.isForced == "on"));

              $.ajax({
                url: createURL("deleteDomain&id=" + args.context.domains[0].id + array1.join("")),
                dataType: "json",
                async: false,
                success: function(json) {
                  var jid = json.deletedomainresponse.jobid;
                  args.response.success(
                    {_custom:
                     {jobId: jid}
                    }
                  );

                  // Quick fix for proper UI reaction to delete domain
                  var $item = $('.name.selected').closest('li');
                  var $itemParent = $item.closest('li');
                  $itemParent.parent().parent().find('.name:first').click();
                  $item.remove();
                }
              });
            },
            notification: {
              poll: pollAsyncJobResult
            }
          },

          // Edit domain
          edit: {
            label: 'label.action.edit.domain',
            messages: {
              notification: function(args) {
                return 'label.action.edit.domain';
              }
            },
            action: function(args) {
              var domainObj;

							var data = {
							  id: args.context.domains[0].id,
							  networkdomain: args.data.networkdomain
							};

							if(args.data.name != null) {
							  $.extend(data, {
								  name: args.data.name
								});
							}

              $.ajax({
                url: createURL("updateDomain"),
                async: false,
                data: data,
                success: function(json) {
                  domainObj = json.updatedomainresponse.domain;
                }
              });

							if(args.data.vmLimit != null) {
								$.ajax({
									url: createURL("updateResourceLimit&domainid=" + args.context.domains[0].id + "&resourceType=0&max=" + args.data.vmLimit),
									dataType: "json",
									async: false,
									success: function(json) {
										domainObj["vmLimit"] = args.data.vmLimit;
									}
								});
							}

							if(args.data.ipLimit != null) {
								$.ajax({
									url: createURL("updateResourceLimit&domainid=" + args.context.domains[0].id + "&resourceType=1&max=" + args.data.ipLimit),
									dataType: "json",
									async: false,
									success: function(json) {
										domainObj["ipLimit"] = args.data.ipLimit;
									}
								});
							}

              if(args.data.volumeLimit != null) {
								$.ajax({
									url: createURL("updateResourceLimit&domainid=" + args.context.domains[0].id + "&resourceType=2&max=" + args.data.volumeLimit),
									dataType: "json",
									async: false,
									success: function(json) {
										domainObj["volumeLimit"] = args.data.volumeLimit;
									}
								});
							}

              if(args.data.snapshotLimit != null) {
								$.ajax({
									url: createURL("updateResourceLimit&domainid=" + args.context.domains[0].id + "&resourceType=3&max=" + args.data.snapshotLimit),
									dataType: "json",
									async: false,
									success: function(json) {
										domainObj["snapshotLimit"] = args.data.snapshotLimit;
									}
								});
							}

              if(args.data.templateLimit != null) {
								$.ajax({
									url: createURL("updateResourceLimit&domainid=" + args.context.domains[0].id + "&resourceType=4&max=" + args.data.templateLimit),
									dataType: "json",
									async: false,
									success: function(json) {
										domainObj["templateLimit"] = args.data.templateLimit;
									}
								});
							}

              if(args.data.vpcLimit != null) {
								$.ajax({
									url: createURL("updateResourceLimit&domainid=" + args.context.domains[0].id + "&resourceType=7&max=" + args.data.vpcLimit),
									dataType: "json",
									async: false,
									success: function(json) {
										domainObj["vpcLimit"] = args.data.vpcLimit;
									}
								});
							}

              args.response.success({data: domainObj});
            }
          },

          // Add domain
          create: {
            label: 'label.add.domain',

            action: function(args) {
              var array1 = [];
              array1.push("&parentdomainid=" + args.context.domains[0].id);
              array1.push("&name=" + todb(args.data.name));
              if(args.data.networkdomain != null && args.data.networkdomain.length > 0)
                array1.push("&networkdomain=" + todb(args.data.networkdomain));

              $.ajax({
                url: createURL("createDomain" + array1.join("")),
                dataType: "json",
                async: false,
                success: function(json) {
                  var item = json.createdomainresponse.domain;
                  args.response.success({data: item});
                },
                error: function(XMLHttpResponse) {
                  var errorMsg = parseXMLHttpResponse(XMLHttpResponse);
                  args.response.error(errorMsg);
                }
              });
            },

            messages: {
              notification: function(args) {
                return 'label.add.domain';
              }
            },

            createForm: {
              title: 'label.add.domain',
              desc: 'message.add.domain',
              fields: {
                name: {
                  label: 'label.name',
                  validation: { required: true }
                },
                networkdomain: {
                  label: 'label.network.domain',
                  validation: { required: false }
                }
              }
            }
          },

					updateResourceCount: {
						label: 'label.action.update.resource.count',
						messages: {
							confirm: function(args) {
								return 'message.update.resource.count';
							},
							notification: function(args) {
								return 'label.action.update.resource.count';
							}
						},
						action: function(args) {
							$.ajax({
								url: createURL("updateResourceCount&domainid=" + args.context.domains[0].id),
								dataType: "json",
								async: true,
								success: function(json) {
									//var resourcecounts= json.updateresourcecountresponse.resourcecount;   //do nothing
									args.response.success();
								}
							});
						},
						notification: {
							poll: function(args) {
								args.complete();
							}
						}
					}
        },
        tabs: {
          details: {
            title: 'label.details',
            fields: [
              {
                name: {
								  label: 'label.name',
									isEditable: function(context) {
                    if(context.domains[0].level != 0) //ROOT domain (whose level is 0) is not allowed to change domain name
										  return true;
										else
											return false;
									}
								}
              },
              {
                id: { label: 'ID' },

								path: { label: 'label.full.path' },

                networkdomain: {
                  label: 'label.network.domain',
                  isEditable: true
                },
                vmLimit: {
                  label: 'label.instance.limits',
                  isEditable: function(context) {
                    if(context.domains[0].level != 0) //ROOT domain (whose level is 0) is not allowed to updateResourceLimits
										  return true;
										else
											return false;
									}
                },
                ipLimit: {
                  label: 'label.ip.limits',
                  isEditable: function(context) {
                    if(context.domains[0].level != 0) //ROOT domain (whose level is 0) is not allowed to updateResourceLimits
										  return true;
										else
											return false;
									}
                },
                volumeLimit: {
                  label: 'label.volume.limits',
                  isEditable: function(context) {
                    if(context.domains[0].level != 0) //ROOT domain (whose level is 0) is not allowed to updateResourceLimits
										  return true;
										else
											return false;
									}
                },
                snapshotLimit: {
                  label: 'label.snapshot.limits',
                  isEditable: function(context) {
                    if(context.domains[0].level != 0) //ROOT domain (whose level is 0) is not allowed to updateResourceLimits
										  return true;
										else
											return false;
									}
                },
                templateLimit: {
                  label: 'label.template.limits',
                  isEditable: function(context) {
                    if(context.domains[0].level != 0) //ROOT domain (whose level is 0) is not allowed to updateResourceLimits
										  return true;
										else
											return false;
									}
                },
                vpcLimit: {
                  label: 'VPC limits',
                  isEditable: function(context) {
                    if(context.domains[0].level != 0) //ROOT domain (whose level is 0) is not allowed to updateResourceLimits
										  return true;
										else
											return false;
									}
                },
                accountTotal: { label: 'label.accounts' },
                vmTotal: { label: 'label.instances' },
                volumeTotal: { label: 'label.volumes' }
              }
            ],
            dataProvider: function(args) {
              var domainObj = args.context.domains[0];
              $.ajax({
                url: createURL("listAccounts&domainid=" + domainObj.id),
                async: false,
                data: {
								  details: 'min'
								},
                success: function(json) {
                  var items = json.listaccountsresponse.account;
                  var total;
                  if (items != null)
                    total = items.length;
                  else
                    total = 0;
                  domainObj["accountTotal"] = total;
                }
              });

              $.ajax({
                url: createURL("listVirtualMachines&details=min&domainid=" + domainObj.id),
                async: false,
                dataType: "json",
                success: function(json) {
                  var items = json.listvirtualmachinesresponse.virtualmachine;
                  var total;
                  if (items != null)
                    total = items.length;
                  else
                    total = 0;
                  domainObj["vmTotal"] = total;
                }
              });

              $.ajax({
                url: createURL("listVolumes&domainid=" + domainObj.id),
                async: false,
                dataType: "json",
                success: function(json) {
                  var items = json.listvolumesresponse.volume;
                  var total;
                  if (items != null)
                    total = items.length;
                  else
                    total = 0;
                  domainObj["volumeTotal"] = total;
                }
              });

              $.ajax({
                url: createURL("listResourceLimits&domainid=" + domainObj.id),
                async: false,
                dataType: "json",
                success: function(json) {
                  var limits = json.listresourcelimitsresponse.resourcelimit;
                  if (limits != null) {
                    for (var i = 0; i < limits.length; i++) {
                      var limit = limits[i];
                      switch (limit.resourcetype) {
                      case "0":
                        domainObj["vmLimit"] = limit.max;
                        break;
                      case "1":
                        domainObj["ipLimit"] = limit.max;
                        break;
                      case "2":
                        domainObj["volumeLimit"] = limit.max;
                        break;
                      case "3":
                        domainObj["snapshotLimit"] = limit.max;
                        break;
                      case "4":
                        domainObj["templateLimit"] = limit.max;
                        break;
                      case "7":
                        domainObj["vpcLimit"] = limit.max;
                        break;
                      }
                    }
                  }
                }
              });

              args.response.success({
                data: domainObj,
                actionFilter: domainActionfilter
              });
            }
          }
        }
      },
      labelField: 'name',
      dataProvider: function(args) {
        var parentDomain = args.context.parentDomain;
        if(parentDomain == null) { //draw root node
          $.ajax({
            url: createURL("listDomains&id=" + g_domainid + '&listAll=true'),
            dataType: "json",
            async: false,
            success: function(json) {
              var domainObjs = json.listdomainsresponse.domain;
              args.response.success({
                actionFilter: domainActionfilter,
                data: domainObjs
              });
            }
          });
        }
        else {
          $.ajax({
            url: createURL("listDomainChildren&id=" + parentDomain.id),
            dataType: "json",
            async: false,
            success: function(json) {
              var domainObjs = json.listdomainchildrenresponse.domain;
              args.response.success({
                actionFilter: domainActionfilter,
                data: domainObjs
              });
            }
          });
        }
      }
    }
  };

  var domainActionfilter = function(args) {
    var jsonObj = args.context.item;
    var allowedActions = [];
    if(isAdmin()) {
      allowedActions.push("create");
			allowedActions.push("edit"); //merge updateResourceLimit into edit
			if(jsonObj.level != 0) { //ROOT domain (whose level is 0) is not allowed to delete
        allowedActions.push("delete");
      }
    }
    allowedActions.push("updateResourceCount");
    return allowedActions;
  }

})(cloudStack);
<commit_msg>bug 15089: cloudstack UI - domain page - get volume count and VM count from listAccounts API response that has volumetotal property and vmtotal property under each account object. listVolumes API and listVirtualMachines API are no longer called when domains are clicked in domain page.<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.
(function(cloudStack) {
  cloudStack.sections.domains = {
    title: 'label.menu.domains',
    id: 'domains',

    // Domain tree
    treeView: {
      // Details
      detailView: {
        name: 'Domain details',
        viewAll: {
          label: 'label.accounts',
          path: 'accounts'
        },

        // Detail actions
        actions: {
          'delete': {
            label: 'label.action.delete.domain',
            messages: {
              notification: function(args) {
                return 'label.action.delete.domain';
              }
            },

            createForm: {
              title: 'label.action.delete.domain',
              desc: 'message.action.delete.domain',
              createLabel: 'label.delete',
              preFilter: function(args) {
                if(isAdmin()) {
                  args.$form.find('.form-item[rel=isForced]').css('display', 'inline-block');
                }
              },
              fields: {
                isForced: {
                  label: 'force.delete',
                  isBoolean: true,
                  isHidden: true
                }
              }
            },

            action: function(args) {
              var array1 = [];
              if(args.$form.find('.form-item[rel=isForced]').css("display") != "none") //uncomment after Brian fix it to include $form in args
                array1.push("&cleanup=" + (args.data.isForced == "on"));

              $.ajax({
                url: createURL("deleteDomain&id=" + args.context.domains[0].id + array1.join("")),
                dataType: "json",
                async: false,
                success: function(json) {
                  var jid = json.deletedomainresponse.jobid;
                  args.response.success(
                    {_custom:
                     {jobId: jid}
                    }
                  );

                  // Quick fix for proper UI reaction to delete domain
                  var $item = $('.name.selected').closest('li');
                  var $itemParent = $item.closest('li');
                  $itemParent.parent().parent().find('.name:first').click();
                  $item.remove();
                }
              });
            },
            notification: {
              poll: pollAsyncJobResult
            }
          },

          // Edit domain
          edit: {
            label: 'label.action.edit.domain',
            messages: {
              notification: function(args) {
                return 'label.action.edit.domain';
              }
            },
            action: function(args) {
              var domainObj;

							var data = {
							  id: args.context.domains[0].id,
							  networkdomain: args.data.networkdomain
							};

							if(args.data.name != null) {
							  $.extend(data, {
								  name: args.data.name
								});
							}

              $.ajax({
                url: createURL("updateDomain"),
                async: false,
                data: data,
                success: function(json) {
                  domainObj = json.updatedomainresponse.domain;
                }
              });

							if(args.data.vmLimit != null) {
								$.ajax({
									url: createURL("updateResourceLimit&domainid=" + args.context.domains[0].id + "&resourceType=0&max=" + args.data.vmLimit),
									dataType: "json",
									async: false,
									success: function(json) {
										domainObj["vmLimit"] = args.data.vmLimit;
									}
								});
							}

							if(args.data.ipLimit != null) {
								$.ajax({
									url: createURL("updateResourceLimit&domainid=" + args.context.domains[0].id + "&resourceType=1&max=" + args.data.ipLimit),
									dataType: "json",
									async: false,
									success: function(json) {
										domainObj["ipLimit"] = args.data.ipLimit;
									}
								});
							}

              if(args.data.volumeLimit != null) {
								$.ajax({
									url: createURL("updateResourceLimit&domainid=" + args.context.domains[0].id + "&resourceType=2&max=" + args.data.volumeLimit),
									dataType: "json",
									async: false,
									success: function(json) {
										domainObj["volumeLimit"] = args.data.volumeLimit;
									}
								});
							}

              if(args.data.snapshotLimit != null) {
								$.ajax({
									url: createURL("updateResourceLimit&domainid=" + args.context.domains[0].id + "&resourceType=3&max=" + args.data.snapshotLimit),
									dataType: "json",
									async: false,
									success: function(json) {
										domainObj["snapshotLimit"] = args.data.snapshotLimit;
									}
								});
							}

              if(args.data.templateLimit != null) {
								$.ajax({
									url: createURL("updateResourceLimit&domainid=" + args.context.domains[0].id + "&resourceType=4&max=" + args.data.templateLimit),
									dataType: "json",
									async: false,
									success: function(json) {
										domainObj["templateLimit"] = args.data.templateLimit;
									}
								});
							}

              if(args.data.vpcLimit != null) {
								$.ajax({
									url: createURL("updateResourceLimit&domainid=" + args.context.domains[0].id + "&resourceType=7&max=" + args.data.vpcLimit),
									dataType: "json",
									async: false,
									success: function(json) {
										domainObj["vpcLimit"] = args.data.vpcLimit;
									}
								});
							}

              args.response.success({data: domainObj});
            }
          },

          // Add domain
          create: {
            label: 'label.add.domain',

            action: function(args) {
              var array1 = [];
              array1.push("&parentdomainid=" + args.context.domains[0].id);
              array1.push("&name=" + todb(args.data.name));
              if(args.data.networkdomain != null && args.data.networkdomain.length > 0)
                array1.push("&networkdomain=" + todb(args.data.networkdomain));

              $.ajax({
                url: createURL("createDomain" + array1.join("")),
                dataType: "json",
                async: false,
                success: function(json) {
                  var item = json.createdomainresponse.domain;
                  args.response.success({data: item});
                },
                error: function(XMLHttpResponse) {
                  var errorMsg = parseXMLHttpResponse(XMLHttpResponse);
                  args.response.error(errorMsg);
                }
              });
            },

            messages: {
              notification: function(args) {
                return 'label.add.domain';
              }
            },

            createForm: {
              title: 'label.add.domain',
              desc: 'message.add.domain',
              fields: {
                name: {
                  label: 'label.name',
                  validation: { required: true }
                },
                networkdomain: {
                  label: 'label.network.domain',
                  validation: { required: false }
                }
              }
            }
          },

					updateResourceCount: {
						label: 'label.action.update.resource.count',
						messages: {
							confirm: function(args) {
								return 'message.update.resource.count';
							},
							notification: function(args) {
								return 'label.action.update.resource.count';
							}
						},
						action: function(args) {
							$.ajax({
								url: createURL("updateResourceCount&domainid=" + args.context.domains[0].id),
								dataType: "json",
								async: true,
								success: function(json) {
									//var resourcecounts= json.updateresourcecountresponse.resourcecount;   //do nothing
									args.response.success();
								}
							});
						},
						notification: {
							poll: function(args) {
								args.complete();
							}
						}
					}
        },
        tabs: {
          details: {
            title: 'label.details',
            fields: [
              {
                name: {
								  label: 'label.name',
									isEditable: function(context) {
                    if(context.domains[0].level != 0) //ROOT domain (whose level is 0) is not allowed to change domain name
										  return true;
										else
											return false;
									}
								}
              },
              {
                id: { label: 'ID' },

								path: { label: 'label.full.path' },

                networkdomain: {
                  label: 'label.network.domain',
                  isEditable: true
                },
                vmLimit: {
                  label: 'label.instance.limits',
                  isEditable: function(context) {
                    if(context.domains[0].level != 0) //ROOT domain (whose level is 0) is not allowed to updateResourceLimits
										  return true;
										else
											return false;
									}
                },
                ipLimit: {
                  label: 'label.ip.limits',
                  isEditable: function(context) {
                    if(context.domains[0].level != 0) //ROOT domain (whose level is 0) is not allowed to updateResourceLimits
										  return true;
										else
											return false;
									}
                },
                volumeLimit: {
                  label: 'label.volume.limits',
                  isEditable: function(context) {
                    if(context.domains[0].level != 0) //ROOT domain (whose level is 0) is not allowed to updateResourceLimits
										  return true;
										else
											return false;
									}
                },
                snapshotLimit: {
                  label: 'label.snapshot.limits',
                  isEditable: function(context) {
                    if(context.domains[0].level != 0) //ROOT domain (whose level is 0) is not allowed to updateResourceLimits
										  return true;
										else
											return false;
									}
                },
                templateLimit: {
                  label: 'label.template.limits',
                  isEditable: function(context) {
                    if(context.domains[0].level != 0) //ROOT domain (whose level is 0) is not allowed to updateResourceLimits
										  return true;
										else
											return false;
									}
                },
                vpcLimit: {
                  label: 'VPC limits',
                  isEditable: function(context) {
                    if(context.domains[0].level != 0) //ROOT domain (whose level is 0) is not allowed to updateResourceLimits
										  return true;
										else
											return false;
									}
                },
                accountTotal: { label: 'label.accounts' },
                vmTotal: { label: 'label.instances' },
                volumeTotal: { label: 'label.volumes' }
              }
            ],
            dataProvider: function(args) {
              var domainObj = args.context.domains[0];
              $.ajax({
                url: createURL("listAccounts&domainid=" + domainObj.id),
                async: false,
                data: {
								  details: 'min'
								},
                success: function(json) {
                  var items = json.listaccountsresponse.account;
                  var total;
                  if (items != null)
                    total = items.length;
                  else
                    total = 0;
                  domainObj["accountTotal"] = total;
                  var itemsAcc;
                  var totalVMs=0;
                  var totalVolumes=0;
                  for(var i=0;i<total;i++) {
                        itemsAcc = json.listaccountsresponse.account[i];
                        totalVMs = totalVMs + itemsAcc.vmtotal;
                        totalVolumes = totalVolumes + itemsAcc.volumetotal;
                  }
                  domainObj["vmTotal"] = totalVMs;
                  domainObj["volumeTotal"] = totalVolumes;

                }
              });

              /* $.ajax({
                url: createURL("listVirtualMachines&details=min&domainid=" + domainObj.id),
                async: false,
                dataType: "json",
                success: function(json) {
                  var items = json.listvirtualmachinesresponse.virtualmachine;
                  var total;
                  if (items != null)
                    total = items.length;
                  else
                    total = 0;
                  domainObj["vmTotal"] = total;
                }
              });

              $.ajax({
                url: createURL("listVolumes&domainid=" + domainObj.id),
                async: false,
                dataType: "json",
                success: function(json) {
                  var items = json.listvolumesresponse.volume;
                  var total;
                  if (items != null)
                    total = items.length;
                  else
                    total = 0;
                  domainObj["volumeTotal"] = total;
                }
              });*/

              $.ajax({
                url: createURL("listResourceLimits&domainid=" + domainObj.id),
                async: false,
                dataType: "json",
                success: function(json) {
                  var limits = json.listresourcelimitsresponse.resourcelimit;
                  if (limits != null) {
                    for (var i = 0; i < limits.length; i++) {
                      var limit = limits[i];
                      switch (limit.resourcetype) {
                      case "0":
                        domainObj["vmLimit"] = limit.max;
                        break;
                      case "1":
                        domainObj["ipLimit"] = limit.max;
                        break;
                      case "2":
                        domainObj["volumeLimit"] = limit.max;
                        break;
                      case "3":
                        domainObj["snapshotLimit"] = limit.max;
                        break;
                      case "4":
                        domainObj["templateLimit"] = limit.max;
                        break;
                      case "7":
                        domainObj["vpcLimit"] = limit.max;
                        break;
                      }
                    }
                  }
                }
              });

              args.response.success({
                data: domainObj,
                actionFilter: domainActionfilter
              });
            }
          }
        }
      },
      labelField: 'name',
      dataProvider: function(args) {
        var parentDomain = args.context.parentDomain;
        if(parentDomain == null) { //draw root node
          $.ajax({
            url: createURL("listDomains&id=" + g_domainid + '&listAll=true'),
            dataType: "json",
            async: false,
            success: function(json) {
              var domainObjs = json.listdomainsresponse.domain;
              args.response.success({
                actionFilter: domainActionfilter,
                data: domainObjs
              });
            }
          });
        }
        else {
          $.ajax({
            url: createURL("listDomainChildren&id=" + parentDomain.id),
            dataType: "json",
            async: false,
            success: function(json) {
              var domainObjs = json.listdomainchildrenresponse.domain;
              args.response.success({
                actionFilter: domainActionfilter,
                data: domainObjs
              });
            }
          });
        }
      }
    }
  };

  var domainActionfilter = function(args) {
    var jsonObj = args.context.item;
    var allowedActions = [];
    if(isAdmin()) {
      allowedActions.push("create");
			allowedActions.push("edit"); //merge updateResourceLimit into edit
			if(jsonObj.level != 0) { //ROOT domain (whose level is 0) is not allowed to delete
        allowedActions.push("delete");
      }
    }
    allowedActions.push("updateResourceCount");
    return allowedActions;
  }

})(cloudStack);
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// @flow

import React, { PureComponent } from 'react';
import explicitConnect from '../../utils/connect';
import { withSize, type SizeProps } from '../shared/WithSize';
import ThreadStackGraph from '../shared/thread/StackGraph';
import ThreadActivityGraph from '../shared/thread/ActivityGraph';
import {
  getProfileInterval,
  getCommittedRange,
  getCategories,
} from '../../selectors/profile';
import { getThreadSelectors } from '../../selectors/per-thread';

import {
  getSelectedThreadIndex,
  getTimelineType,
} from '../../selectors/url-state';
import {
  TimelineMarkersJank,
  TimelineMarkersFileIo,
  TimelineMarkersOverview,
  TimelineMarkersMemory,
} from './Markers';
import {
  updatePreviewSelection,
  changeRightClickedTrack,
  changeSelectedCallNode,
  focusCallTree,
  selectLeafCallNode,
  selectBestAncestorCallNodeAndExpandCallTree,
} from '../../actions/profile-view';
import { reportTrackThreadHeight } from '../../actions/app';
import EmptyThreadIndicator from './EmptyThreadIndicator';
import './TrackThread.css';

import type { TimelineType } from '../../types/actions';
import type {
  Thread,
  ThreadIndex,
  CategoryList,
  IndexIntoSamplesTable,
} from '../../types/profile';
import type { Milliseconds, StartEndRange } from '../../types/units';
import type {
  CallNodeInfo,
  IndexIntoCallNodeTable,
  SelectedState,
} from '../../types/profile-derived';
import type { State } from '../../types/state';
import type { ConnectedProps } from '../../utils/connect';

type OwnProps = {|
  +threadIndex: ThreadIndex,
  +showMemoryMarkers?: boolean,
|};

type StateProps = {|
  +fullThread: Thread,
  +filteredThread: Thread,
  +callNodeInfo: CallNodeInfo,
  +selectedCallNodeIndex: IndexIntoCallNodeTable | null,
  +unfilteredSamplesRange: StartEndRange | null,
  +interval: Milliseconds,
  +rangeStart: Milliseconds,
  +rangeEnd: Milliseconds,
  +categories: CategoryList,
  +timelineType: TimelineType,
  +hasFileIoMarkers: boolean,
  +samplesSelectedStates: null | SelectedState[],
|};

type DispatchProps = {|
  +changeRightClickedTrack: typeof changeRightClickedTrack,
  +updatePreviewSelection: typeof updatePreviewSelection,
  +changeSelectedCallNode: typeof changeSelectedCallNode,
  +focusCallTree: typeof focusCallTree,
  +selectLeafCallNode: typeof selectLeafCallNode,
  +selectBestAncestorCallNodeAndExpandCallTree: typeof selectBestAncestorCallNodeAndExpandCallTree,
  +reportTrackThreadHeight: typeof reportTrackThreadHeight,
|};

type Props = {|
  ...SizeProps,
  ...ConnectedProps<OwnProps, StateProps, DispatchProps>,
|};

class TimelineTrackThread extends PureComponent<Props> {
  /**
   * Handle when a sample is clicked in the ThreadStackGraph. This will select
   * the leaf-most stack frame or call node.
   */
  _onSampleClick = (sampleIndex: IndexIntoSamplesTable) => {
    const { threadIndex, selectLeafCallNode, focusCallTree } = this.props;
    selectLeafCallNode(threadIndex, sampleIndex);
    focusCallTree();
  };

  _onActivitySampleClick = (sampleIndex: IndexIntoSamplesTable) => {
    const {
      threadIndex,
      selectBestAncestorCallNodeAndExpandCallTree,
      focusCallTree,
    } = this.props;
    selectBestAncestorCallNodeAndExpandCallTree(threadIndex, sampleIndex);
    focusCallTree();
  };

  _onMarkerSelect = (
    threadIndex: ThreadIndex,
    start: Milliseconds,
    end: Milliseconds
  ) => {
    const { rangeStart, rangeEnd, updatePreviewSelection } = this.props;
    updatePreviewSelection({
      hasSelection: true,
      isModifying: false,
      selectionStart: Math.max(rangeStart, start),
      selectionEnd: Math.min(rangeEnd, end),
    });
  };

  componentDidUpdate() {
    const { threadIndex, height, reportTrackThreadHeight } = this.props;
    // Most likely this track height shouldn't change, but if it does, report it.
    // The action will only dispatch on changed values.
    reportTrackThreadHeight(threadIndex, height);
  }

  render() {
    const {
      filteredThread,
      fullThread,
      threadIndex,
      interval,
      rangeStart,
      rangeEnd,
      callNodeInfo,
      selectedCallNodeIndex,
      unfilteredSamplesRange,
      categories,
      timelineType,
      hasFileIoMarkers,
      showMemoryMarkers,
      samplesSelectedStates,
    } = this.props;

    const processType = filteredThread.processType;
    const displayJank = processType !== 'plugin';
    const displayMarkers =
      (filteredThread.name === 'GeckoMain' ||
        filteredThread.name === 'Compositor' ||
        filteredThread.name === 'Renderer') &&
      processType !== 'plugin';

    return (

        {showMemoryMarkers ? (
          <TimelineMarkersMemory
            rangeStart={rangeStart}
            rangeEnd={rangeEnd}
            threadIndex={threadIndex}
            onSelect={this._onMarkerSelect}
          />
        ) : null}
        {hasFileIoMarkers ? (
          <TimelineMarkersFileIo
            rangeStart={rangeStart}
            rangeEnd={rangeEnd}
            threadIndex={threadIndex}
            onSelect={this._onMarkerSelect}
          />
        ) : null}
        {displayJank ? (
          <TimelineMarkersJank
            rangeStart={rangeStart}
            rangeEnd={rangeEnd}
            threadIndex={threadIndex}
            onSelect={this._onMarkerSelect}
          />
        ) : null}
        {displayMarkers ? (
          <TimelineMarkersOverview
            rangeStart={rangeStart}
            rangeEnd={rangeEnd}
            threadIndex={threadIndex}
            onSelect={this._onMarkerSelect}
          />
        ) : null}
        {timelineType === 'category' && !filteredThread.isJsTracer ? (
          <ThreadActivityGraph
            className="threadActivityGraph"
            interval={interval}
            fullThread={fullThread}
            rangeStart={rangeStart}
            rangeEnd={rangeEnd}
            onSampleClick={this._onActivitySampleClick}
            categories={categories}
            samplesSelectedStates={samplesSelectedStates}
          />
        ) : (
          <ThreadStackGraph
            className="threadStackGraph"
            interval={interval}
            thread={filteredThread}
            rangeStart={rangeStart}
            rangeEnd={rangeEnd}
            callNodeInfo={callNodeInfo}
            selectedCallNodeIndex={selectedCallNodeIndex}
            categories={categories}
            onSampleClick={this._onSampleClick}
          />
        )}
        <EmptyThreadIndicator
          thread={filteredThread}
          interval={interval}
          rangeStart={rangeStart}
          rangeEnd={rangeEnd}
          unfilteredSamplesRange={unfilteredSamplesRange}
        />

    );
  }
}

export default explicitConnect<OwnProps, StateProps, DispatchProps>({
  mapStateToProps: (state: State, ownProps: OwnProps) => {
    const { threadIndex } = ownProps;
    const selectors = getThreadSelectors(threadIndex);
    const selectedThread = getSelectedThreadIndex(state);
    const committedRange = getCommittedRange(state);
    const selectedCallNodeIndex =
      threadIndex === selectedThread
        ? selectors.getSelectedCallNodeIndex(state)
        : null;
    return {
      filteredThread: selectors.getFilteredThread(state),
      fullThread: selectors.getRangeFilteredThread(state),
      callNodeInfo: selectors.getCallNodeInfo(state),
      selectedCallNodeIndex,
      unfilteredSamplesRange: selectors.unfilteredSamplesRange(state),
      interval: getProfileInterval(state),
      rangeStart: committedRange.start,
      rangeEnd: committedRange.end,
      categories: getCategories(state),
      timelineType: getTimelineType(state),
      hasFileIoMarkers: selectors.getFileIoMarkerIndexes(state).length !== 0,
      samplesSelectedStates: selectors.getSamplesSelectedStatesInFilteredThread(
        state
      ),
    };
  },
  mapDispatchToProps: {
    updatePreviewSelection,
    changeRightClickedTrack,
    changeSelectedCallNode,
    focusCallTree,
    selectLeafCallNode,
    selectBestAncestorCallNodeAndExpandCallTree,
    reportTrackThreadHeight,
  },
  component: withSize<Props>(TimelineTrackThread),
});
<commit_msg>Add a comment for _onActivitySampleClick<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// @flow

import React, { PureComponent } from 'react';
import explicitConnect from '../../utils/connect';
import { withSize, type SizeProps } from '../shared/WithSize';
import ThreadStackGraph from '../shared/thread/StackGraph';
import ThreadActivityGraph from '../shared/thread/ActivityGraph';
import {
  getProfileInterval,
  getCommittedRange,
  getCategories,
} from '../../selectors/profile';
import { getThreadSelectors } from '../../selectors/per-thread';

import {
  getSelectedThreadIndex,
  getTimelineType,
} from '../../selectors/url-state';
import {
  TimelineMarkersJank,
  TimelineMarkersFileIo,
  TimelineMarkersOverview,
  TimelineMarkersMemory,
} from './Markers';
import {
  updatePreviewSelection,
  changeRightClickedTrack,
  changeSelectedCallNode,
  focusCallTree,
  selectLeafCallNode,
  selectBestAncestorCallNodeAndExpandCallTree,
} from '../../actions/profile-view';
import { reportTrackThreadHeight } from '../../actions/app';
import EmptyThreadIndicator from './EmptyThreadIndicator';
import './TrackThread.css';

import type { TimelineType } from '../../types/actions';
import type {
  Thread,
  ThreadIndex,
  CategoryList,
  IndexIntoSamplesTable,
} from '../../types/profile';
import type { Milliseconds, StartEndRange } from '../../types/units';
import type {
  CallNodeInfo,
  IndexIntoCallNodeTable,
  SelectedState,
} from '../../types/profile-derived';
import type { State } from '../../types/state';
import type { ConnectedProps } from '../../utils/connect';

type OwnProps = {|
  +threadIndex: ThreadIndex,
  +showMemoryMarkers?: boolean,
|};

type StateProps = {|
  +fullThread: Thread,
  +filteredThread: Thread,
  +callNodeInfo: CallNodeInfo,
  +selectedCallNodeIndex: IndexIntoCallNodeTable | null,
  +unfilteredSamplesRange: StartEndRange | null,
  +interval: Milliseconds,
  +rangeStart: Milliseconds,
  +rangeEnd: Milliseconds,
  +categories: CategoryList,
  +timelineType: TimelineType,
  +hasFileIoMarkers: boolean,
  +samplesSelectedStates: null | SelectedState[],
|};

type DispatchProps = {|
  +changeRightClickedTrack: typeof changeRightClickedTrack,
  +updatePreviewSelection: typeof updatePreviewSelection,
  +changeSelectedCallNode: typeof changeSelectedCallNode,
  +focusCallTree: typeof focusCallTree,
  +selectLeafCallNode: typeof selectLeafCallNode,
  +selectBestAncestorCallNodeAndExpandCallTree: typeof selectBestAncestorCallNodeAndExpandCallTree,
  +reportTrackThreadHeight: typeof reportTrackThreadHeight,
|};

type Props = {|
  ...SizeProps,
  ...ConnectedProps<OwnProps, StateProps, DispatchProps>,
|};

class TimelineTrackThread extends PureComponent<Props> {
  /**
   * Handle when a sample is clicked in the ThreadStackGraph. This will select
   * the leaf-most stack frame or call node.
   */
  _onSampleClick = (sampleIndex: IndexIntoSamplesTable) => {
    const { threadIndex, selectLeafCallNode, focusCallTree } = this.props;
    selectLeafCallNode(threadIndex, sampleIndex);
    focusCallTree();
  };

  /**
   * Handle when the ThreadActivityGraph is clicked. It uses a slightly different
   * strategy of selecting the "best" ancestor call node for a given sample.
   * This strategy should make for more interesting selections when clicking around
   * the graph.
   */
  _onActivitySampleClick = (sampleIndex: IndexIntoSamplesTable) => {
    const {
      threadIndex,
      selectBestAncestorCallNodeAndExpandCallTree,
      focusCallTree,
    } = this.props;
    selectBestAncestorCallNodeAndExpandCallTree(threadIndex, sampleIndex);
    focusCallTree();
  };

  _onMarkerSelect = (
    threadIndex: ThreadIndex,
    start: Milliseconds,
    end: Milliseconds
  ) => {
    const { rangeStart, rangeEnd, updatePreviewSelection } = this.props;
    updatePreviewSelection({
      hasSelection: true,
      isModifying: false,
      selectionStart: Math.max(rangeStart, start),
      selectionEnd: Math.min(rangeEnd, end),
    });
  };

  componentDidUpdate() {
    const { threadIndex, height, reportTrackThreadHeight } = this.props;
    // Most likely this track height shouldn't change, but if it does, report it.
    // The action will only dispatch on changed values.
    reportTrackThreadHeight(threadIndex, height);
  }

  render() {
    const {
      filteredThread,
      fullThread,
      threadIndex,
      interval,
      rangeStart,
      rangeEnd,
      callNodeInfo,
      selectedCallNodeIndex,
      unfilteredSamplesRange,
      categories,
      timelineType,
      hasFileIoMarkers,
      showMemoryMarkers,
      samplesSelectedStates,
    } = this.props;

    const processType = filteredThread.processType;
    const displayJank = processType !== 'plugin';
    const displayMarkers =
      (filteredThread.name === 'GeckoMain' ||
        filteredThread.name === 'Compositor' ||
        filteredThread.name === 'Renderer') &&
      processType !== 'plugin';

    return (

        {showMemoryMarkers ? (
          <TimelineMarkersMemory
            rangeStart={rangeStart}
            rangeEnd={rangeEnd}
            threadIndex={threadIndex}
            onSelect={this._onMarkerSelect}
          />
        ) : null}
        {hasFileIoMarkers ? (
          <TimelineMarkersFileIo
            rangeStart={rangeStart}
            rangeEnd={rangeEnd}
            threadIndex={threadIndex}
            onSelect={this._onMarkerSelect}
          />
        ) : null}
        {displayJank ? (
          <TimelineMarkersJank
            rangeStart={rangeStart}
            rangeEnd={rangeEnd}
            threadIndex={threadIndex}
            onSelect={this._onMarkerSelect}
          />
        ) : null}
        {displayMarkers ? (
          <TimelineMarkersOverview
            rangeStart={rangeStart}
            rangeEnd={rangeEnd}
            threadIndex={threadIndex}
            onSelect={this._onMarkerSelect}
          />
        ) : null}
        {timelineType === 'category' && !filteredThread.isJsTracer ? (
          <ThreadActivityGraph
            className="threadActivityGraph"
            interval={interval}
            fullThread={fullThread}
            rangeStart={rangeStart}
            rangeEnd={rangeEnd}
            onSampleClick={this._onActivitySampleClick}
            categories={categories}
            samplesSelectedStates={samplesSelectedStates}
          />
        ) : (
          <ThreadStackGraph
            className="threadStackGraph"
            interval={interval}
            thread={filteredThread}
            rangeStart={rangeStart}
            rangeEnd={rangeEnd}
            callNodeInfo={callNodeInfo}
            selectedCallNodeIndex={selectedCallNodeIndex}
            categories={categories}
            onSampleClick={this._onSampleClick}
          />
        )}
        <EmptyThreadIndicator
          thread={filteredThread}
          interval={interval}
          rangeStart={rangeStart}
          rangeEnd={rangeEnd}
          unfilteredSamplesRange={unfilteredSamplesRange}
        />

    );
  }
}

export default explicitConnect<OwnProps, StateProps, DispatchProps>({
  mapStateToProps: (state: State, ownProps: OwnProps) => {
    const { threadIndex } = ownProps;
    const selectors = getThreadSelectors(threadIndex);
    const selectedThread = getSelectedThreadIndex(state);
    const committedRange = getCommittedRange(state);
    const selectedCallNodeIndex =
      threadIndex === selectedThread
        ? selectors.getSelectedCallNodeIndex(state)
        : null;
    return {
      filteredThread: selectors.getFilteredThread(state),
      fullThread: selectors.getRangeFilteredThread(state),
      callNodeInfo: selectors.getCallNodeInfo(state),
      selectedCallNodeIndex,
      unfilteredSamplesRange: selectors.unfilteredSamplesRange(state),
      interval: getProfileInterval(state),
      rangeStart: committedRange.start,
      rangeEnd: committedRange.end,
      categories: getCategories(state),
      timelineType: getTimelineType(state),
      hasFileIoMarkers: selectors.getFileIoMarkerIndexes(state).length !== 0,
      samplesSelectedStates: selectors.getSamplesSelectedStatesInFilteredThread(
        state
      ),
    };
  },
  mapDispatchToProps: {
    updatePreviewSelection,
    changeRightClickedTrack,
    changeSelectedCallNode,
    focusCallTree,
    selectLeafCallNode,
    selectBestAncestorCallNodeAndExpandCallTree,
    reportTrackThreadHeight,
  },
  component: withSize<Props>(TimelineTrackThread),
});
<|endoftext|>


<commit_before>let step = undefined;
let prevStep = undefined;
let isFinished = false;

let timeout = 120;
let tickInterval = 500;
let monitorPulse = undefined;

console.log("deleter injected");
start();

function start() {
	console.log('delete: starting');
	step = waitForLoad;
	doStep(0);
}

function doStep(tick) {
	if (tick > timeout && prevStep === step) {
		step = done;
		step();
		return;
	}

	if (tick % 25 === 0) {
		console.log('something is stalled... ' + tick + '/' + timeout);
	}

	if (prevStep !== step) {
		prevStep = step;
		tick = 0;
	}

	step();
	window.setTimeout(doStep, tickInterval, tick + 1);
}

function waitForLoad() {
	if (isDeleted()) {
		step = done;
		return;
	}

	let arrow = getArrow();
	if (arrow) {
		step = openDropdown;
	}
}

function openDropdown() {
	let arrow = getArrow();
	arrow.click();
	step = waitForDropdownOpened;
}

function waitForDropdownOpened() {
	let delPostButton = getDeletePostButton();
	if (delPostButton) {
		step = clickDeletePost;
	}
}

function clickDeletePost() {
	let deletePostButton = getDeletePostButton();
	deletePostButton.click();
	step = waitForDeleteAvailable;
}

function waitForDeleteAvailable() {
	let deleteButton = getDeleteButton();
	if (deleteButton) {
		step = clickDelete
	}
}

function clickDelete() {
	let deleteButton = getDeleteButton();
	deleteButton.click();
	step = done;
}

function done() {
	// this may get called multiple times since the
	// timer is still going
	if (isFinished) {
		return;
	}

	isFinished = true;
	browser.runtime.sendMessage({
		to: "deleter",
		body: window.location.href
	});
}

function isDeleted() {
	let content = 'This post has been removed or could not be loaded.';
	let elems = document.getElementsByTagName('div');

	for (let elem of elems) {
		if (elem.innerHTML === content) {
			return true;
		}
	}

	return false;
}

function getArrow() {
	let elems = document.getElementsByTagName('a');
	for (let elem of elems) {
		if (elem.getAttribute('aria-label') === 'Story options') {
			return elem;
		}
	}

	return null;
}

function getDeletePostButton() {
	let elems = document.getElementsByTagName('div');
	for (let elem of elems) {
		if (isDeletePostButton(elem)) {
			return elem;
		}
	}

	return null;
}

function isDeletePostButton(elem) {
	return (
		elem.childNodes.length === 3 &&
		elem.childNodes[2].nodeValue === 'Delete post')
	);
}

function getDeleteButton() {
	let elems = document.getElementsByTagName('button');
	for (let elem of elems) {
		if (isDeleteButton(elem)) {
			return elem;
		}
	}

	return null;
}

function isDeleteButton(elem) {
	let deleteMessage = "Delete";
	let noSoldMessage = "Haven't Sold";

	return (
		elem.innerHTML === deleteMessage ||
		elem.innerHTML === noSoldMessage
	);
}
<commit_msg>Refactored deleter<commit_after>let step = undefined;
let prevStep = undefined;
let isFinished = false;

let timeout = 120;
let tickInterval = 500;
let monitorPulse = undefined;

console.log("deleter injected");
start();

function start() {
	console.log('delete: starting');
	step = openMenu;
	doStep(0);
}

function doStep(tick) {
	if (tick > timeout && prevStep === step) {
		step = done;
		step();
		return;
	}

	if (tick % 25 === 0) {
		console.log('something is stalled... ' + tick + '/' + timeout);
	}

	if (prevStep !== step) {
		prevStep = step;
		tick = 0;
	}

	step();
	window.setTimeout(doStep, tickInterval, tick + 1);
}

function openMenu() {
	let deleteMessage = getElement('div', isDeleteMessage);
	if (deleteMessage) {
		step = done;
		return;
	}

	let arrow = getElement('a', isArrow);
	if (arrow) {
		arrow.click();
		step = clickDeletePostOption;
	}
}

function clickDeletePostOption() {
	let deletePostOption = getElement('div', isDeletePostOption);
	if (deletePostOption) {
		deletePostOption.click();
		step = clickDeleteButton;
	}
}

function clickDeleteButton() {
	let deleteButton = getElement('button', isDeleteButton);
	if (deleteButton) {
		deleteButton.click();
		step = done;
	}
}

function done() {
	// this may get called multiple times since the
	// timer is still going
	if (isFinished) {
		return;
	}

	isFinished = true;
	browser.runtime.sendMessage({
		to: "deleter",
		body: window.location.href
	});
}

function getElement(tagName, predicate) {
	let elems = document.getElementsByTagName(tagName);
	for (let elem of elems) {
		if (predicate(elem)) {
			return elem;
		}
	}

	return null;
}

function isDeleteMessage(elem) {
	let content = 'This post has been removed or could not be loaded.';
	return (elem.innerHTML === content);
}

function isArrow(elem) {
	return (elem.getAttribute('aria-label') === 'Story options');
}

function isDeletePostOption(elem) {
	return (
		elem.childNodes.length === 3 &&
		elem.childNodes[2].nodeValue === 'Delete post')
	);
}

function isDeleteButton(elem) {
	let deleteMessage = "Delete";
	let noSoldMessage = "Haven't Sold";

	return (
		elem.innerHTML === deleteMessage ||
		elem.innerHTML === noSoldMessage
	);
}
<|endoftext|>


<commit_before>// NOTICE!! DO NOT USE ANY OF THIS JAVASCRIPT
// IT'S ALL JUST JUNK FOR OUR DOCS!
// ++++++++++++++++++++++++++++++++++++++++++

/*!
 * JavaScript for Bootstrap's docs (http://getbootstrap.com)
 * Copyright 2011-2014 Twitter, Inc.
 * Licensed under the Creative Commons Attribution 3.0 Unported License. For
 * details, see http://creativecommons.org/licenses/by/3.0/.
 */

/* global ZeroClipboard */

!function ($) {
  'use strict';

  $(function () {

    // Scrollspy
    var $window = $(window)
    var $body   = $(document.body)

    $body.scrollspy({
      target: '.bs-docs-sidebar'
    })
    $window.on('load', function () {
      $body.scrollspy('refresh')
    })

    // Kill links
    $('.bs-docs-container [href=#]').click(function (e) {
      e.preventDefault()
    })

    // Sidenav affixing
    setTimeout(function () {
      var $sideBar = $('.bs-docs-sidebar')

      $sideBar.affix({
        offset: {
          top: function () {
            var offsetTop      = $sideBar.offset().top
            var sideBarMargin  = parseInt($sideBar.children(0).css('margin-top'), 10)
            var navOuterHeight = $('.bs-docs-nav').height()

            return (this.top = offsetTop - navOuterHeight - sideBarMargin)
          },
          bottom: function () {
            return (this.bottom = $('.bs-docs-footer').outerHeight(true))
          }
        }
      })
    }, 100)

    setTimeout(function () {
      $('.bs-top').affix()
    }, 100)

    // theme toggler
    ;(function () {
      var stylesheetLink = $('#bs-theme-stylesheet')
      var themeBtn = $('.bs-docs-theme-toggle')
      themeBtn.click(function () {
        var href = stylesheetLink.attr('href');
        if (!href || href.indexOf('data') === 0) {
          stylesheetLink.attr('href', stylesheetLink.attr('data-href'))
          themeBtn.text('Disable theme preview')
        }
        else {
          stylesheetLink.attr('href', '')
          themeBtn.text('Preview theme')
        }
      })
    })();

    // Tooltip and popover demos
    $('.tooltip-demo').tooltip({
      selector: '[data-toggle="tooltip"]',
      container: 'body'
    })
    $('.popover-demo').popover({
      selector: '[data-toggle="popover"]',
      container: 'body'
    })

    // Demos within modals
    $('.tooltip-test').tooltip()
    $('.popover-test').popover()

    // Default & dismissible popover demos
    $('.bs-docs-popover').popover()
    $('.bs-docs-popover-dismiss').popover({ trigger: 'focus' })

    // Button state demo
    $('#loading-example-btn').click(function () {
      var btn = $(this)
      btn.button('loading')
      setTimeout(function () {
        btn.button('reset')
      }, 3000)
    })

    // Config ZeroClipboard
    ZeroClipboard.config({
      moviePath: '/assets/flash/ZeroClipboard.swf',
      hoverClass: 'btn-clipboard-hover'
    })

    // Insert copy to clipboard button before .highlight or .bs-example
    $('.highlight').each(function () {
      var highlight = $(this)
      var previous = highlight.prev()
      var btnHtml = '
Copy
'

      if (previous.hasClass('bs-example')) {
        previous.before(btnHtml.replace(/btn-clipboard/, 'btn-clipboard with-example'))
      } else {
        highlight.before(btnHtml)
      }
    })
    var zeroClipboard = new ZeroClipboard($('.btn-clipboard'))
    var htmlBridge = $('#global-zeroclipboard-html-bridge')

    // Handlers for ZeroClipboard
    zeroClipboard.on('load', function () {
      htmlBridge
        .data('placement', 'top')
        .attr('title', 'Copy to clipboard')
        .tooltip()
    })

    // Copy to clipboard
    zeroClipboard.on('dataRequested', function (client) {
      var highlight = $(this).parent().nextAll('.highlight').first()
      client.setText(highlight.text())
    })

    // Notify copy success and reset tooltip title
    zeroClipboard.on('complete', function () {
      htmlBridge
        .attr('title', 'Copied!')
        .tooltip('fixTitle')
        .tooltip('show')
        .attr('title', 'Copy to clipboard')
        .tooltip('fixTitle')
    })

    // Notify copy failure
    zeroClipboard.on('noflash wrongflash', function () {
      htmlBridge
        .attr('title', 'Flash required')
        .tooltip('fixTitle')
        .tooltip('show')
    })

  })

}(jQuery)
<commit_msg>Save "Preview theme" state; resolves #13940<commit_after>// NOTICE!! DO NOT USE ANY OF THIS JAVASCRIPT
// IT'S ALL JUST JUNK FOR OUR DOCS!
// ++++++++++++++++++++++++++++++++++++++++++

/*!
 * JavaScript for Bootstrap's docs (http://getbootstrap.com)
 * Copyright 2011-2014 Twitter, Inc.
 * Licensed under the Creative Commons Attribution 3.0 Unported License. For
 * details, see http://creativecommons.org/licenses/by/3.0/.
 */

/* global ZeroClipboard */

!function ($) {
  'use strict';

  $(function () {

    // Scrollspy
    var $window = $(window)
    var $body   = $(document.body)

    $body.scrollspy({
      target: '.bs-docs-sidebar'
    })
    $window.on('load', function () {
      $body.scrollspy('refresh')
    })

    // Kill links
    $('.bs-docs-container [href=#]').click(function (e) {
      e.preventDefault()
    })

    // Sidenav affixing
    setTimeout(function () {
      var $sideBar = $('.bs-docs-sidebar')

      $sideBar.affix({
        offset: {
          top: function () {
            var offsetTop      = $sideBar.offset().top
            var sideBarMargin  = parseInt($sideBar.children(0).css('margin-top'), 10)
            var navOuterHeight = $('.bs-docs-nav').height()

            return (this.top = offsetTop - navOuterHeight - sideBarMargin)
          },
          bottom: function () {
            return (this.bottom = $('.bs-docs-footer').outerHeight(true))
          }
        }
      })
    }, 100)

    setTimeout(function () {
      $('.bs-top').affix()
    }, 100)

    // theme toggler
    ;(function () {
      var stylesheetLink = $('#bs-theme-stylesheet')
      var themeBtn = $('.bs-docs-theme-toggle')

      var activateTheme = function () {
        stylesheetLink.attr('href', stylesheetLink.attr('data-href'))
        themeBtn.text('Disable theme preview')
        localStorage.setItem('previewTheme', true)
      }

      if (localStorage.getItem('previewTheme')) {
        activateTheme()
      }

      themeBtn.click(function () {
        var href = stylesheetLink.attr('href')
        if (!href || href.indexOf('data') === 0) {
          activateTheme()
        } else {
          stylesheetLink.attr('href', '')
          themeBtn.text('Preview theme')
          localStorage.removeItem('previewTheme')
        }
      })
    })();

    // Tooltip and popover demos
    $('.tooltip-demo').tooltip({
      selector: '[data-toggle="tooltip"]',
      container: 'body'
    })
    $('.popover-demo').popover({
      selector: '[data-toggle="popover"]',
      container: 'body'
    })

    // Demos within modals
    $('.tooltip-test').tooltip()
    $('.popover-test').popover()

    // Default & dismissible popover demos
    $('.bs-docs-popover').popover()
    $('.bs-docs-popover-dismiss').popover({ trigger: 'focus' })

    // Button state demo
    $('#loading-example-btn').click(function () {
      var btn = $(this)
      btn.button('loading')
      setTimeout(function () {
        btn.button('reset')
      }, 3000)
    })

    // Config ZeroClipboard
    ZeroClipboard.config({
      moviePath: '/assets/flash/ZeroClipboard.swf',
      hoverClass: 'btn-clipboard-hover'
    })

    // Insert copy to clipboard button before .highlight or .bs-example
    $('.highlight').each(function () {
      var highlight = $(this)
      var previous = highlight.prev()
      var btnHtml = '
Copy
'

      if (previous.hasClass('bs-example')) {
        previous.before(btnHtml.replace(/btn-clipboard/, 'btn-clipboard with-example'))
      } else {
        highlight.before(btnHtml)
      }
    })
    var zeroClipboard = new ZeroClipboard($('.btn-clipboard'))
    var htmlBridge = $('#global-zeroclipboard-html-bridge')

    // Handlers for ZeroClipboard
    zeroClipboard.on('load', function () {
      htmlBridge
        .data('placement', 'top')
        .attr('title', 'Copy to clipboard')
        .tooltip()
    })

    // Copy to clipboard
    zeroClipboard.on('dataRequested', function (client) {
      var highlight = $(this).parent().nextAll('.highlight').first()
      client.setText(highlight.text())
    })

    // Notify copy success and reset tooltip title
    zeroClipboard.on('complete', function () {
      htmlBridge
        .attr('title', 'Copied!')
        .tooltip('fixTitle')
        .tooltip('show')
        .attr('title', 'Copy to clipboard')
        .tooltip('fixTitle')
    })

    // Notify copy failure
    zeroClipboard.on('noflash wrongflash', function () {
      htmlBridge
        .attr('title', 'Flash required')
        .tooltip('fixTitle')
        .tooltip('show')
    })

  })

}(jQuery)
<|endoftext|>


<commit_before>var AfterHook = module.exports = function (done) {
    this.browser.end(done);
};
<commit_msg>#49: Fix unclosed session problem in after hook<commit_after>var AfterHook = module.exports = function (done) {
    this.browser.end().then(done);
};
<|endoftext|>


<commit_before>/**
 * Parse source and update TestCase. Throw an exception if any error occurs.
 *
 * @param testCase TestCase to update
 * @param source The source to parse
 */
function parse(testCase, source) {
	var doc = source;
  var commands = [];
  testCase.header = this.options.header;
  testCase.footer = '';
  while (doc.length > 0) {
    var line = /(.*)(\r\n|[\r\n])?/.exec(doc);
    if (line[1] && line[1].match(/^\|/)) {
      var array = line[1].split(/\|/);
      if (array.length >= 3) {
        var command = new Command();
        command.command = array[1];
        command.target = array[2];
        if (array.length > 3) command.value = array[3];
        commands.push(command);
      }
      testCase.footer = '';
    } else if (commands.length == 0) {
      testCase.header += line[0];
    } else {
      testCase.footer += line[0];
    }
    doc = doc.substr(line[0].length);
  }
  testCase.setCommands(commands);
}

/**
 * Format TestCase and return the source.
 *
 * @param testCase TestCase to format
 * @param name The name of the test case, if any. It may be used to embed title into the source.
 */
function format(testCase, name) {

  var className = testCase.getTitle();
  if (!className) {
    className = "perform actions and see result";
  }

  var content = formatCommands(testCase.commands);

 /* var formatLocal = testCase.formatLocal(this.name);
  methodName = testMethodName(className.replace(/Test$/, "").replace(/^Test/, "").
                replace(/^[A-Z]/, function(str) { return str.toLowerCase(); }));*/

    var cept = options.header.
    replace(/\$\{baseURL\}/g, testCase.getBaseURL()).
    replace(/\$\{action\}/g, className).
    replace(/\$\{content\}/g, content).
    replace(/\$\{([a-zA-Z0-9_]+)\}/g, function(str, name) { return options[name]; });

  return cept;

}

/**
 * Format an array of commands to the snippet of source.
 * Used to copy the source into the clipboard.
 *
 * @param The array of commands to sort.
 */
function formatCommands(commands, indent = 0) {
	var result = '';
  var ignoreWebCommands = ['answerOnNextPrompt'];
  for (var i = 0; i < commands.length; i++) {
    var command = commands[i];
    var tmpResult = formatCommand(command, indent);

    if (ignoreWebCommands.indexOf(command.command) == -1) {
      result += indents(indent) + options.variable + tmpResult;
    }
  }

  return result;
}

//Store temp value for prompt
var promptValue = "";

function formatCommand(command, indent) {
  var result = "";

  if (command.type == 'command') {

      var codeceptionCommand = '';

      //Switch command and replace with codeception varient
      switch (command.command) {
        case 'open':
          result += '->amOnPage("'+command.target+'");\n';
          break;
        case 'click':
        case 'clickAndWait':
          var target = getSelector(command.target);
          result += '->click("'+target+'");\n';
          break;
        case 'select':
          var target = getSelector(command.target);
          var value = command.value.split('=')[1];
          result += '->selectOption("'+target+'", "'+value+'");\n';
          break;
        case 'sendKeys':
          var target = getSelector(command.target);
          result += '->appendField("'+target+'", "'+command.value+'");\n';
          break;
        case 'type':
          var target = getSelector(command.target);
          result += '->fillField("'+target+'", "'+command.value+'");\n';
          break;
        case 'dragAndDropToObject':
          var target = getSelector(command.target);
          var value = getSelector(command.value);
          result += '->dragAndDrop("'+target+'", "'+value+'");\n';
          break;
        case 'assertText':
          if (command.target.substring(0, 4) === 'link') {
            result += '->see("'+command.value+'");\n';
          } else {
            var target = getSelector(command.target);
            result += '->see("'+command.value+'", "'+target+'");\n';
          }
          break;
        case 'assertNotText':
            var target = getSelector(command.target);
            result += '->dontSee("'+command.value+'", "'+target+'");\n';
          break;
        case 'waitForElementPresent':
            var target = getSelector(command.target);
            result += '->waitForElement("'+target+'");\n';
          break;
        case 'waitForText':
        case 'waitForTextPresent':
          if (command.target) {
            var target = getSelector(command.target);
            result += '->waitForText("'+ command.value+'",'+10+ ' , "'+target+'");\n';
          } else {
            result += '->waitForText("'+ command.value+'",'+10+ ');\n';
          }

          break;
        case 'assertTextNotPresent':
          if (command.target) {
            var target = getSelector(command.target);
            result += '->dontSee("'+ command.value+'", "'+target+'");\n';
          } else {
            result += '->dontSee("'+ command.value+'");\n';
          }
          break;
        case 'addSelection':
            var target = getSelector(command.target);
            var value = command.value.split('=')[1];
            result += '->appendField("'+target+'", "'+ value+'");\n';
          break;
        case 'removeSelection':
            var target = getSelector(command.target);
            var value = command.value.split('=')[1];
            result += '->unselectOption("'+target+'", "'+ value+'");\n';
          break;
        case 'verifyValue':
        case 'assertValue':
            var target = getSelector(command.target);
            var value = command.value.replace('exact:', '');
            result += '->seeInField("'+target+'", "'+ value +'");\n';
          break;
        case 'verifyChecked':
            var target = getSelector(command.target);
            var value = command.value.replace('exact:', '');
            result += '->seeCheckboxIsChecked("'+target+'");\n';
          break;
        case 'verifySelectedValue':
        case 'verifySelectedLabel':
            var target = getSelector(command.target);
            result += '->seeOptionIsSelected("'+target+'", "'+ command.value+'");\n';
          break;
        case 'verifyElementNotPresent':
          //Throws value undefined error if no target is given, selenium ide bug
            result += '->dontSeeElement("'+ command.value +'");\n';
          break;
        case 'answerOnNextPrompt':
            promptValue = command.target;
            break;
        case 'assertPrompt':
            result += '->typeInPopup("'+promptValue+'");\n';
            promptValue = '';
          break;

          default:
          result += '->' + command.command + '====' + command.target + '|' + command.value + "|\n";
      }

    }

    return result;
}

function escapeString(value)
{
  return value.replace(/"/g, '\\"');
}

function getSelector(target) {

  //Check for xparth
  if (target.substring(0, 2) === '//') {
    return target;
  } else {

    var parts = target.split(/=(.+)?/);
    parts[1] = escapeString(parts[1]);

    switch(parts[0]) {
      case 'id':
          return "#"+parts[1];
        break;
      case 'css':
          return parts[1];
        break;
      case 'name':
        return 'input[name='+parts[1]+']';
        break;
      case 'link':
        return parts[1];
        break;
      case 'xpath':
        return parts[1];
      default:
        alert('unknown selector: '+parts[0]+'  value: '+parts[1]);
    }
  }
}

/**
 * Returns a string representing the suite for this formatter language.
 *
 * @param testSuite  the suite to format
 * @param filename   the file the formatted suite will be saved as
 */
function formatSuite(testSuite, filename) {
  var suiteClass = /^(\w+)/.exec(filename)[1];
  suiteClass = suiteClass[0].toUpperCase() + suiteClass.substring(1);

  var formattedSuite = "";

  for (var i = 0; i < testSuite.tests.length; ++i) {
    var content = "";

    //If the filename is set then use this as the method name
    //Otherwise we use the test case title, which will be
    //Untitled as a default
    var testCase = "";
    if (testSuite.tests[i].filename) {
      testCase = testSuite.tests[i].filename;
    } else {
      testCase = testSuite.tests[i].getTitle();
    }

    testClass = testCase.
    replace(/\s/g, '_').
    replace(/\//g, '_');

    var action = testSuite.tests[i].getTitle();

    if (!testSuite.tests[i].content) {
      //Open the testcase, formats the commands from the stored html
      editor.app.showTestCaseFromSuite(testSuite.tests[i]);
    }
    //Get the actions for this test
    content = formatCommands(testSuite.tests[i].content.commands, 2);

    var testFunction = options.testClassHeader.
    replace(/\$\{testClass\}/g, testClass).
    replace(/\$\{content\}/g, content).
    replace(/\$\{action\}/g, action).
    replace(/\$\{([a-zA-Z0-9_]+)\}/g, function(str, name) { return options[name]; });

    formattedSuite +=  testFunction + "\n\n";
  }

  var cest = options.testHeader.
    replace(/\$\{suiteClass\}/g, suiteClass).
    replace(/\$\{content\}/g, formattedSuite).
    replace(/\$\{([a-zA-Z0-9_]+)\}/g, function(str, name) { return options[name]; });

  return cest;
}

function formatHeader(testCase) {
  var className = testCase.getTitle();
  if (!className) {
    className = "NewTest";
  }
  className = testClassName(className);
  var formatLocal = testCase.formatLocal(this.name);
  methodName = testMethodName(className.replace(/Test$/i, "").replace(/^Test/i, "").replace(/^[A-Z]/, function(str) {
    return str.toLowerCase();
  }));
  var header = (options.getHeader ? options.getHeader() : options.header).
      replace(/\$\{className\}/g, className).
      replace(/\$\{methodName\}/g, methodName).
      replace(/\$\{baseURL\}/g, testCase.getBaseURL()).
      replace(/\$\{([a-zA-Z0-9_]+)\}/g, function(str, name) {
        return options[name];
      });
  this.lastIndent = indents(parseInt(options.initialIndents, 10));
  formatLocal.header = header;
  return formatLocal.header;
}

function formatFooter(testCase) {
  var formatLocal = testCase.formatLocal(this.name);
  formatLocal.footer = options.footer;
  return formatLocal.footer;
}

function indents(num) {
  function repeat(c, n) {
    var str = "";
    for (var i = 0; i < n; i++) {
      str += c;
    }
    return str;
  }

  try {
    var indent = options.indent;
    if ('tab' == indent) {
      return repeat("\t", num);
    } else {
      return repeat(" ", num * parseInt(options.indent, 10));
    }
  } catch (error) {
    return repeat(" ", 0);
  }
}

function capitalize(string) {
  return string.replace(/^[a-z]/, function(str) {
    return str.toUpperCase();
  });
}

function underscore(text) {
  return text.replace(/[A-Z]/g, function(str) {
    return '_' + str.toLowerCase();
  });

}

/*
 * Optional: The customizable option that can be used in format/parse functions.
 */
options = {
  header: '<?php\n'
    + '${variable} = new WebGuy($scenario);\n'
    + '${variable}->wantTo("${action}");\n'
    + '${content}\n',
  testHeader: "<?php\n\n"
    + "class ${suiteClass}"
    + '{\n'
    + indents(2) + "protected ${variable};\n\n"
    + indents(2) + "public function _before() {}\n"
    + indents(2) + "public function _after() {}\n\n"
    + indents(2) + "${content}\n\n"
    + '}',
  testClassHeader: 'public function ${testClass} (\Webguy ${variable})\n'
    + '{\n\n'
    + '${variable}->wantTo("${action}");\n'
    + '${content}\n'
    + '}',
  indent: 4,
  variable: '$I'
}

/*
 * Optional: XUL XML String for the UI of the options dialog
 */
//configForm = '<textbox id="options_nameOfTheOption"/>'

this.configForm =
        '<description>Variable for WebGuy 123</description>' +
        '<textbox id="options_variable" />' +
        '<description>Cept</description>' +
        '<textbox id="options_header" multiline="true" flex="1" rows="4"/>' +
        '<description>Cest</description>' +
        '<textbox id="options_testHeader" multiline="true" flex="1" rows="4"/>' +
        '<description>Cest Function</description>' +
        '<textbox id="options_testClassHeader" multiline="true" flex="1" rows="2"/>' +
        '<description>Indent</description>' +
        '<menulist id="options_indent"><menupopup>' +
        '<menuitem label="Tab" value="tab"/>' +
        '<menuitem label="1 space" value="1"/>' +
        '<menuitem label="2 spaces" value="2"/>' +
        '<menuitem label="3 spaces" value="3"/>' +
        '<menuitem label="4 spaces" value="4"/>' +
        '<menuitem label="5 spaces" value="5"/>' +
        '<menuitem label="6 spaces" value="6"/>' +
        '<menuitem label="7 spaces" value="7"/>' +
        '<menuitem label="8 spaces" value="8"/>' +
        '</menupopup></menulist>';
<commit_msg>- Added move function support - refresh - verifyNotText - verifyText<commit_after>/**
 * Parse source and update TestCase. Throw an exception if any error occurs.
 *
 * @param testCase TestCase to update
 * @param source The source to parse
 */
function parse(testCase, source) {
	var doc = source;
  var commands = [];
  testCase.header = this.options.header;
  testCase.footer = '';
  while (doc.length > 0) {
    var line = /(.*)(\r\n|[\r\n])?/.exec(doc);
    if (line[1] && line[1].match(/^\|/)) {
      var array = line[1].split(/\|/);
      if (array.length >= 3) {
        var command = new Command();
        command.command = array[1];
        command.target = array[2];
        if (array.length > 3) command.value = array[3];
        commands.push(command);
      }
      testCase.footer = '';
    } else if (commands.length == 0) {
      testCase.header += line[0];
    } else {
      testCase.footer += line[0];
    }
    doc = doc.substr(line[0].length);
  }
  testCase.setCommands(commands);
}

/**
 * Format TestCase and return the source.
 *
 * @param testCase TestCase to format
 * @param name The name of the test case, if any. It may be used to embed title into the source.
 */
function format(testCase, name) {

  var className = testCase.getTitle();
  if (!className) {
    className = "perform actions and see result";
  }

  var content = formatCommands(testCase.commands);

 /* var formatLocal = testCase.formatLocal(this.name);
  methodName = testMethodName(className.replace(/Test$/, "").replace(/^Test/, "").
                replace(/^[A-Z]/, function(str) { return str.toLowerCase(); }));*/

    var cept = options.header.
    replace(/\$\{baseURL\}/g, testCase.getBaseURL()).
    replace(/\$\{action\}/g, className).
    replace(/\$\{content\}/g, content).
    replace(/\$\{([a-zA-Z0-9_]+)\}/g, function(str, name) { return options[name]; });

  return cept;

}

/**
 * Format an array of commands to the snippet of source.
 * Used to copy the source into the clipboard.
 *
 * @param The array of commands to sort.
 */
function formatCommands(commands, indent = 0) {
	var result = '';
  var ignoreWebCommands = ['answerOnNextPrompt'];
  for (var i = 0; i < commands.length; i++) {
    var command = commands[i];
    var tmpResult = formatCommand(command, indent);

    if (ignoreWebCommands.indexOf(command.command) == -1) {
      result += indents(indent) + options.variable + tmpResult;
    }
  }

  return result;
}

//Store temp value for prompt
var promptValue = "";

function formatCommand(command, indent) {
  var result = "";

  if (command.type == 'command') {

      var codeceptionCommand = '';

      //Switch command and replace with codeception varient
      switch (command.command) {
        case 'open':
          result += '->amOnPage("'+command.target+'");\n';
          break;
        case 'click':
        case 'clickAndWait':
          var target = getSelector(command.target);
          result += '->click("'+target+'");\n';
          break;
        case 'select':
          var target = getSelector(command.target);
          var value = command.value.split('=')[1];
          result += '->selectOption("'+target+'", "'+value+'");\n';
          break;
        case 'sendKeys':
          var target = getSelector(command.target);
          result += '->appendField("'+target+'", "'+command.value+'");\n';
          break;
        case 'type':
          var target = getSelector(command.target);
          result += '->fillField("'+target+'", "'+command.value+'");\n';
          break;
        case 'dragAndDropToObject':
          var target = getSelector(command.target);
          var value = getSelector(command.value);
          result += '->dragAndDrop("'+target+'", "'+value+'");\n';
          break;
        case 'verifyText':
        case 'assertText':
          if (command.target.substring(0, 4) === 'link') {
            result += '->see("'+command.value+'");\n';
          } else {
            var target = getSelector(command.target);
            result += '->see("'+command.value+'", "'+target+'");\n';
          }
          break;
        case 'verifyNotText':
        case 'assertNotText':
            var target = getSelector(command.target);
            result += '->dontSee("'+command.value+'", "'+target+'");\n';
          break;
        case 'waitForElementPresent':
            var target = getSelector(command.target);
            result += '->waitForElement("'+target+'");\n';
          break;
        case 'waitForText':
        case 'waitForTextPresent':
          if (command.target) {
            var target = getSelector(command.target);
            result += '->waitForText("'+ command.value+'",'+10+ ' , "'+target+'");\n';
          } else {
            result += '->waitForText("'+ command.value+'",'+10+ ');\n';
          }

          break;
        case 'assertTextNotPresent':
          if (command.target) {
            var target = getSelector(command.target);
            result += '->dontSee("'+ command.value+'", "'+target+'");\n';
          } else {
            result += '->dontSee("'+ command.value+'");\n';
          }
          break;
        case 'addSelection':
            var target = getSelector(command.target);
            var value = command.value.split('=')[1];
            result += '->appendField("'+target+'", "'+ value+'");\n';
          break;
        case 'removeSelection':
            var target = getSelector(command.target);
            var value = command.value.split('=')[1];
            result += '->unselectOption("'+target+'", "'+ value+'");\n';
          break;
        case 'verifyValue':
        case 'assertValue':
            var target = getSelector(command.target);
            var value = command.value.replace('exact:', '');
            result += '->seeInField("'+target+'", "'+ value +'");\n';
          break;
        case 'verifyChecked':
            var target = getSelector(command.target);
            var value = command.value.replace('exact:', '');
            result += '->seeCheckboxIsChecked("'+target+'");\n';
          break;
        case 'verifySelectedValue':
        case 'verifySelectedLabel':
            var target = getSelector(command.target);
            result += '->seeOptionIsSelected("'+target+'", "'+ command.value+'");\n';
          break;
        case 'verifyElementNotPresent':
          //Throws value undefined error if no target is given, selenium ide bug
            result += '->dontSeeElement("'+ command.value +'");\n';
          break;
        case 'answerOnNextPrompt':
            promptValue = command.target;
            break;
        case 'assertPrompt':
            result += '->typeInPopup("'+promptValue+'");\n';
            promptValue = '';
          break;
        case 'refresh':
            result += '->reloadPage();\n';
          break;

          default:
          result += '->' + command.command + '====' + command.target + '|' + command.value + "|\n";
      }

    }

    return result;
}

function escapeString(value)
{
  return value.replace(/"/g, '\\"');
}

function getSelector(target) {

  //Check for xparth
  if (target.substring(0, 2) === '//') {
    return target;
  } else {

    var parts = target.split(/=(.+)?/);
    parts[1] = escapeString(parts[1]);

    switch(parts[0]) {
      case 'id':
          return "#"+parts[1];
        break;
      case 'css':
          return parts[1];
        break;
      case 'name':
        return 'input[name='+parts[1]+']';
        break;
      case 'link':
        return parts[1];
        break;
      case 'xpath':
        return parts[1];
      default:
        alert('unknown selector: '+parts[0]+'  value: '+parts[1]);
    }
  }
}

/**
 * Returns a string representing the suite for this formatter language.
 *
 * @param testSuite  the suite to format
 * @param filename   the file the formatted suite will be saved as
 */
function formatSuite(testSuite, filename) {
  var suiteClass = /^(\w+)/.exec(filename)[1];
  suiteClass = suiteClass[0].toUpperCase() + suiteClass.substring(1);

  var formattedSuite = "";

  for (var i = 0; i < testSuite.tests.length; ++i) {
    var content = "";

    //If the filename is set then use this as the method name
    //Otherwise we use the test case title, which will be
    //Untitled as a default
    var testCase = "";
    if (testSuite.tests[i].filename) {
      testCase = testSuite.tests[i].filename;
    } else {
      testCase = testSuite.tests[i].getTitle();
    }

    testClass = testCase.
    replace(/\s/g, '_').
    replace(/\//g, '_');

    var action = testSuite.tests[i].getTitle();

    if (!testSuite.tests[i].content) {
      //Open the testcase, formats the commands from the stored html
      editor.app.showTestCaseFromSuite(testSuite.tests[i]);
    }
    //Get the actions for this test
    content = formatCommands(testSuite.tests[i].content.commands, 2);

    var testFunction = options.testClassHeader.
    replace(/\$\{testClass\}/g, testClass).
    replace(/\$\{content\}/g, content).
    replace(/\$\{action\}/g, action).
    replace(/\$\{([a-zA-Z0-9_]+)\}/g, function(str, name) { return options[name]; });

    formattedSuite +=  testFunction + "\n\n";
  }

  var cest = options.testHeader.
    replace(/\$\{suiteClass\}/g, suiteClass).
    replace(/\$\{content\}/g, formattedSuite).
    replace(/\$\{([a-zA-Z0-9_]+)\}/g, function(str, name) { return options[name]; });

  return cest;
}

function formatHeader(testCase) {
  var className = testCase.getTitle();
  if (!className) {
    className = "NewTest";
  }
  className = testClassName(className);
  var formatLocal = testCase.formatLocal(this.name);
  methodName = testMethodName(className.replace(/Test$/i, "").replace(/^Test/i, "").replace(/^[A-Z]/, function(str) {
    return str.toLowerCase();
  }));
  var header = (options.getHeader ? options.getHeader() : options.header).
      replace(/\$\{className\}/g, className).
      replace(/\$\{methodName\}/g, methodName).
      replace(/\$\{baseURL\}/g, testCase.getBaseURL()).
      replace(/\$\{([a-zA-Z0-9_]+)\}/g, function(str, name) {
        return options[name];
      });
  this.lastIndent = indents(parseInt(options.initialIndents, 10));
  formatLocal.header = header;
  return formatLocal.header;
}

function formatFooter(testCase) {
  var formatLocal = testCase.formatLocal(this.name);
  formatLocal.footer = options.footer;
  return formatLocal.footer;
}

function indents(num) {
  function repeat(c, n) {
    var str = "";
    for (var i = 0; i < n; i++) {
      str += c;
    }
    return str;
  }

  try {
    var indent = options.indent;
    if ('tab' == indent) {
      return repeat("\t", num);
    } else {
      return repeat(" ", num * parseInt(options.indent, 10));
    }
  } catch (error) {
    return repeat(" ", 0);
  }
}

function capitalize(string) {
  return string.replace(/^[a-z]/, function(str) {
    return str.toUpperCase();
  });
}

function underscore(text) {
  return text.replace(/[A-Z]/g, function(str) {
    return '_' + str.toLowerCase();
  });

}

/*
 * Optional: The customizable option that can be used in format/parse functions.
 */
options = {
  header: '<?php\n'
    + '${variable} = new WebGuy($scenario);\n'
    + '${variable}->wantTo("${action}");\n'
    + '${content}\n',
  testHeader: "<?php\n\n"
    + "class ${suiteClass}"
    + '{\n'
    + indents(2) + "protected ${variable};\n\n"
    + indents(2) + "public function _before() {}\n"
    + indents(2) + "public function _after() {}\n\n"
    + indents(2) + "${content}\n\n"
    + '}',
  testClassHeader: 'public function ${testClass} (\Webguy ${variable})\n'
    + '{\n\n'
    + '${variable}->wantTo("${action}");\n'
    + '${content}\n'
    + '}',
  indent: 4,
  variable: '$I'
}

/*
 * Optional: XUL XML String for the UI of the options dialog
 */
//configForm = '<textbox id="options_nameOfTheOption"/>'

this.configForm =
        '<description>Variable for WebGuy 123</description>' +
        '<textbox id="options_variable" />' +
        '<description>Cept</description>' +
        '<textbox id="options_header" multiline="true" flex="1" rows="4"/>' +
        '<description>Cest</description>' +
        '<textbox id="options_testHeader" multiline="true" flex="1" rows="4"/>' +
        '<description>Cest Function</description>' +
        '<textbox id="options_testClassHeader" multiline="true" flex="1" rows="2"/>' +
        '<description>Indent</description>' +
        '<menulist id="options_indent"><menupopup>' +
        '<menuitem label="Tab" value="tab"/>' +
        '<menuitem label="1 space" value="1"/>' +
        '<menuitem label="2 spaces" value="2"/>' +
        '<menuitem label="3 spaces" value="3"/>' +
        '<menuitem label="4 spaces" value="4"/>' +
        '<menuitem label="5 spaces" value="5"/>' +
        '<menuitem label="6 spaces" value="6"/>' +
        '<menuitem label="7 spaces" value="7"/>' +
        '<menuitem label="8 spaces" value="8"/>' +
        '</menupopup></menulist>';
<|endoftext|>