SPICEWORKS.plugin.add(     { name:"Help Desk Responses", version:"0.10", description:"A way to define common ticket responses.  Fully commented for those wanting to learn more about how plugins are built.", guid:"p-597aa800-9708-012b-81c0-0016353cc494-1229461086", settings:{"responses":"[{\"name\": \"Close Job\", \"text\": \"\\n\\n* * Please only reply to this email if you want the ticket to be re-opened * *\"}, {\"name\": \"Awaiting Response\", \"text\": \"\\n\\nYou have raised a ticket with us and we are waiting for a response from you.\\n\\nThe ticket will be closed.\\n\\nYou can re-open the ticket by replying to this email.\\n\\n* * Please only reply to this email if you want the ticket to be re-opened * *\"}, {\"name\": \"Labour Request\", \"text\": \"You have requested an onsite engineer / remote support / workshop repair.\\n\\nPlease reply saying \\\"YES\\\" to this email.\\n\\nAn engineer will be arranged once you accept our charges (see below) and our terms and conditions (see website)\\n\\nThe ticket is on hold until we have received the reply.\\n\\nOnsite Engineer\\n=============\\nStandard Business Hours:  Mon - Fri - 09:00 - 17:00 - \u00a350 + VAT (per hour)\\nOut Of Standard Business Hours - \u00a3100 + VAT (per hour)\\n\\nWorkshop Repair\\n=============\\nStandard Business Hours:  Mon - Fri - 09:00 - 17:00 - \u00a330 + VAT (per hour)\\nOut Of Standard Business Hours - \u00a3100 + VAT (per hour)\\n\\nRemote Support\\n=============\\nStandard Business Hours:  Mon - Fri - 09:00 - 17:00 - \u00a330 + VAT (per hour)\\nOut Of Standard Business Hours - \u00a3100 + VAT (per hour)\"}, {\"name\": \"Purchase Request\", \"text\": \"You have requested a purchase.\\n\\nPlease reply saying \\\"YES\\\" to this email.\\n\\nYour goods will be arranged once you accept our charges (see below) and our terms and conditions (see website)\\n\\nThe ticket is on hold until we have received the reply.\\n\\nPurchase Details:\\n\\nNOD Antivirus\\n\u00a350 + VAT\"}, {\"name\": \"Domain Renew\", \"text\": \"The following domain name is up for renewal:\\n\\n\\n\\nIt will cost \u00a399 + VAT to renew this domain name for the next 2 years.\\n\\nIf you do not renew it, you will loose all email addresses and websites associated with the name.\\n\\nPlease can you confirm if you want us to renew it for you?\"}, {\"name\": \"Access The PC?\", \"text\": \"We need to access your computer via remote control.\\n\\nPlease follow the below steps:\\n\\n1. Reply saying \\\"YES\\\" to this email when we can control your computer.\\n2. Reply to this email with any passwords that the computer uses\\n3. Ensure that all programs that are open have been closed down first.\\n4. We will leave a message on the screen when we have finished with the computer.\\n5. Do not touch your computer until we have left a message to say we have finished\\n6. If your computer looks like it is not doing anything, it is because we are running remote tests. Please do not touch your computer until we have put a message on your screen to say that we have finished.\"}, {\"name\": \"Run ShowMyPC\", \"text\": \"We need to access your computer via remote control.\\n\\nPlease follow the below steps:\\n\\n1. Go to http://www.securedatauk.com/setup2.exe\\n2. Click open or run (you may have to do this twice)\\n3. Run the software\\n4. Click on Show My PC Now\\n5. A Long number is generated (example 12345-678910)\\n6. Please email the long number to us\\n7. We will leave a message on the screen when we have finished with the computer.\\n8. Do not touch your computer until we have left a message to say we have finished\\n9. If your computer looks like it is not doing anything, it is because we are running remote tests. Please do not touch your computer until we have put a message on your screen to say \\n\\nYou must minimize and keep the ShowMyPC program running (! Do not close the program ! ).\"}, {\"name\": \"Test It\", \"text\": \"Please can you test the issue that you have been having.\\n\\nCan you please comment back or close the ticket.\"}, {\"name\": \"Reboot\", \"text\": \"Please reboot your machine and try again.\\n\\nCan you please comment back or close the ticket.\"}, {\"name\": \"Log out\", \"text\": \"Please try logging out entirely, and then logging in again.\\n\\nCan you please comment back or close the ticket.\"}, {\"name\": \"Get Internet IP\", \"text\": \"We need you internet IP address.\\n\\nPlease follow the below steps:\\n\\n1. Go to http://www.whatsmyip.org/\\n2. Please email us the IP Address (the long number)\"}, {\"name\": \"Get Phone IP on Snom 320\", \"text\": \"Can you please get the IP Address for the phone by pressing the following keys:\\n\\n- ? (help)\\n- first button under your LCD display (for IPAdr)\\n- then press the cross (X) to cancel\\n\\nCan you please send me the number on your phone display.\"}, {\"name\": \"Get Phone IP on Snom 300\", \"text\": \"Can you please get the IP Address for the phone by pressing the following keys:\\n\\n- On Silver Circle, Press Down\\n- On Silver Circle, Press Up\\n- Press Tick\\n\\nCan you please send me the number that appears on your display.\"}, {\"name\": \"Get Phone IP on Linksys\", \"text\": \"Can you please get the IP Address for the phone by pressing the following keys:\\n\\n- Press The Button With The Symbol Of Paper\\n- Press 9\\n\\nCan you please send me the number that appears under current IP\"}, {\"name\": \"Card Details Needed\", \"text\": \"We need update card details.\\n\\nPlease could you send us the following details:\\n\\nYour Details:\\nFirst Name:\\nLast Name:\\nBilling Address (Include Postcode):\\n\\nCard Number:\\nName On Appears On Card:\\nStart Date:\\nEnd Date:\\nIssue Number:\\nLast Three Digits On Back Of Card:\\nCard Billing Address (Include Postcode):\"}]","link_text":"Auto Response"}, contentAreas: [{"content_type":"text/plain","updated_at":"2010/01/04 12:45:28 +0000","id":14,"description":null,"content_name":"README","user_id":null},{"content_type":"text/javascript","updated_at":"2010/01/04 12:45:28 +0000","id":15,"description":null,"content_name":"initialize.js","user_id":null},{"content_type":"text/css","updated_at":"2010/01/04 12:45:28 +0000","id":16,"description":null,"content_name":"plugin.css","user_id":null}], initialize:function(plugin){ plugin.includeStyles();

defineResponsesEditor();
configurePlugin();
addResponsesToHelpDesk();

// Define the responses editor that we'll be using to edit the responses.  This is used in configure plugin.
function defineResponsesEditor() {

  // CUSTOM FIELD TYPE
  // Let's create a custom editor called "responses_editor".  This will give us a better experience for defining settings.
  // NOTE: A field is just a function that adds content to an element, then returns a getter and a setter for that content.
  SPICEWORKS.field.registerFieldType({
    typeName: 'responses_editor',
    operators: [], // no operators allowed on hidden fields, doesn't make sense.
    buildEditor: function (element, fieldDef) {
      var addDiv, textarea, listElem, editorArea, newResponseItem, message, parent, id = element.id + "_value", itemEditorMap = {};   

      element.style.display = 'block';

      // temporary hack: replace P with DIV (makes ie7 work. won't need this after patch)
      if (element.nodeName === 'P') {
        parent = element.up();
        element.remove();
        parent.insert( element = new Element('div', {'class':''}));      
      }

      listElem = new Element('ul', {'id':'response_list_ul', 'class':'response_list'});
      element.insert(listElem);

      newResponseItem = addNewResponse();

      editorArea = new Element('div', {'class':'response_editor_area'});  
      element.insert(editorArea);

      editorArea.insert(message = new Element('h2').update('&larr; Select a response to edit, or create a new one.'));

      listElem.observe('click',function (e) {
        Event.stop(e);
        $$('div.response_editor_area div.response_editor_wrap').invoke('hide');
        $$('ul.response_list li').invoke('removeClassName', 'selected');
        message.show();
      });

      // Adds the response list item and associated editor to the appropriate parts of the page.
      function addResponse(res) {
        var listItem, itemName, editorWrap, nameEditor, textEditor, showListItem, deleteElem;
        window.response = res;

        editorWrap = new Element('div', {'class':'response_editor_wrap'});
        editorArea.insert(editorWrap);

        nameEditor = new Element('input', {'class':'response_name_editor text', 'value':res.name});
        editorWrap.insert(nameEditor);

        textEditor = new Element('textarea', {'class':'response_text_editor text', 'autocomplete':'off'});
        textEditor.value = res.text;
        editorWrap.insert(textEditor);


        listItem = new Element('li', {'class':'response_list_item'});
        deleteElem = new Element('a', {'class':'delete_response'});
        itemName = new Element('span').update(res.name);

        listItem.insert(deleteElem);
        listItem.insert(itemName);
        newResponseItem.insert({before: listItem});

        editorWrap.hide();

        itemEditorMap[listItem.identify()] = editorWrap;


        // EVENTS
        listItem.observe('click', function (e) {
          Event.stop(e);
          showListItem();        
        });

        listItem.observe('mouseover', function (e) {
          Event.stop(e);
          listItem.addClassName('hover');
        });

        listItem.observe('mouseout', function (e){
          Event.stop(e);
          listItem.removeClassName('hover');
        });

        deleteElem.observe('click', function (e) {
          Event.stop(e);
          if (confirm('Are you sure you want to delete this response?')) {
            listItem.remove();
            editorWrap.remove();
            $$('div.response_editor_area div.response_editor_wrap').invoke('hide');
            message.show();
          }
        });
        nameEditor.observe('keyup', function (e) {
          itemName.innerHTML = nameEditor.value;
        });

        // helper function to select the list item and show the editor.
        function showListItem() {
          $$('div.response_editor_area div.response_editor_wrap').invoke('hide');
          $$('ul.response_list li').invoke('removeClassName', 'selected');
          listItem.addClassName('selected');
          editorWrap.show();
          message.hide();
        }

        return {
          show: showListItem
        };
      }

      // Add the link to create a new response.
      function addNewResponse() {
        newResponseItem = new Element('li', {'class':'new_response_link'}).update('New Response...');
        listElem.insert(newResponseItem);

        newResponseItem.observe('mouseover', function (e) {
          Event.stop(e);
          newResponseItem.addClassName('hover');
        });
        newResponseItem.observe('mouseout', function (e){
          Event.stop(e);
          newResponseItem.removeClassName('hover');
        });
        newResponseItem.observe('click', function (e) {
          Event.stop(e);
          Sortable.destroy('response_list_ul');
          addResponse({name:'New Response', text:'Modify this to be your text!'}).show();
          Sortable.create('response_list_ul', {only:'response_list_item'});
        });
        return newResponseItem;
      }

      // Return get/set methods.  These methods will act on the elements that we defined and inserted above and will be called by the framework (you'll never
      // call them yourself).
      return {
        // Grab text from the text area an split on ~~~~ then create JSON with the name/text of each response.
        get: function () {
          var responses = [];

          $$('li.response_list_item').each(function (li) {
            var editorWrap = itemEditorMap[li.id];
            responses.push({
              name: editorWrap.down('.response_name_editor').value,
              text: editorWrap.down('.response_text_editor').value
            });            
          });

          return responses.length==0 ? null : Object.toJSON(responses);
        },

        // Parse JSON into the appropriate textarea value.
        set: function (value) {
          if (value) {
            value.evalJSON().each(addResponse);
            setTimeout( function () {
              Sortable.create('response_list_ul', {only:'response_list_item'});
            }, 100);
          }
        }
      };
    }
  });

} // end defineResponsesEditor()


// PLUGIN CONFIGURATION
// The configuration is what's displayed when the user clicks "configure" in /settings/plugins.  If this section is excluded,
// then no configure link will appear.
// There's only one configuration and that's the responses.  By default, we dump in some helper text to guide the user.
function configurePlugin() {
  var settingDefs = [];
  settingDefs.push({name:'link_text', label:'Link Text', type:'string', defaultValue:'Append'});
  settingDefs.push({
    name:'responses', label:'Responses', type:'responses_editor', 
    defaultValue: Object.toJSON([
      {"name":"Reboot", "text":"Please reboot your machine and try again."},
      {"name":"Log out", "text":"Please try logging out entirely, and then logging in again."}
    ])
  });

  plugin.configure({
    settingDefinitions: settingDefs
  });  
}



// Add the responses to the helpdesk if that's where we are.
function addResponsesToHelpDesk() {
  var responses = plugin.settings.responses.evalJSON();

  // REGISTER FOR TICKET READY EVENT
  // Each time the ticket is "ready" (loaded) we need to make sure we add the arrow and the div.
  SPICEWORKS.app.helpdesk.ticket.comments.ready(function () {
    var tipText, theTip, hideTimer, response, commentDiv;

    setupResponses();

    if (!$('add_comment_details')) {
      return; // Ticket is most likely closed...
    }

    // If the arrow is already there, then we already did this and should just return without doing anything.
    if($('append_link') || $('append_arrow')) {
      return;
    } else {
      setupAppendLink();
    }

    // Set up the events for the mouseover/outs
    Event.observe(response, 'mouseover', mouseover);
    Event.observe(theTip, 'mouseover', mouseover);
    Event.observe(response, 'mouseout', mouseout);
    Event.observe(theTip, 'mouseout', mouseout);


    // Create the responses menu
    function setupResponses() {
      tipText = new Element('ul', {'style':'margin:0px'});
      responses.each(function (response) {
        var li, link;
        li = new Element('li');
        link = new Element('a', {href:'#', 'class':'icon helpdesk_response_link'});
        li.insert(link);
        link.innerHTML = response.name;
        link.observe('click', function (event) {
          Event.stop(event);
          theTip.hide();

          $('comment_body').focus();
          setTimeout( function () {            
            $('comment_body').value = $('comment_body').value + response.text;
          }, 10); // timeout will allow help message to be cleaned out first.
          return false; 
        });
        tipText.insert( li );
      });      
    }


    // Helper Functions for shoing/hiding the menu at the appropriate times.
    // Uses a timer to make everything play nice together.
    function mouseover(event){
      Event.stop(event);
      clearTimeout(hideTimer);
      if (!theTip.visible()) {
        theTip.clonePosition(response, {
          setWidth:false,
          setHeight:false,
          offsetTop:response.offsetHeight
        });

        theTip.show();
      }

    }
    function mouseout(event){
      Event.stop(event);
      clearTimeout(hideTimer);
      hideTimer = setTimeout(function () {
        theTip.hide();
      }, 200);
    }

    function setupAppendLink() {
      commentDiv = $('add_comment_details');

      // Create the Arrow link and add it to the page
      response = new Element('a', {id:'append_link', href: '#', border:'0'});
      response.innerHTML = plugin.settings['link_text'];
      commentDiv.insert({'top': response});

      // Add the response choices to a pivotable menu (this is a css class defined by spiceworks and used for all menus)
      theTip = new Element('div', {'id':'response_choices', 'class':'pivotable', 'style':'display:none'});
      theTip.update(tipText);
      commentDiv.insert(theTip);

    }

  }); // end ticket.ready

} // end addResponsesToHelpDesk


      }
    }
 );
