UNPKG

@phoenix-plugin-registry/jshint.configurator

Version:

Enables configuration of JSHint options. Reads from current document's inline configuration directive or from '.jshintrc' configuration file. Extract JSHint options to JSON format.

349 lines (297 loc) 13.4 kB
/*jshint browser: true, devel: true, jquery: true, node: true*/ /*global Mustache, brackets, define*/ define(function (require, exports) { 'use strict'; var Dialogs = brackets.getModule('widgets/Dialogs'), EditorManager = brackets.getModule('editor/EditorManager'), DocumentManager = brackets.getModule('document/DocumentManager'), OptionsTemplate = require('text!html/options.html'), Strings = require('strings'), FileExtension = require('services/file_extension'), JSHintConfig = require('services/read_config'), rxJSHintOptions = /^(?:\/\/|\/\*)\s*jshint\s*([^/]*?)\s*(?:\*\/)?$/, rxJSHintValue = /^([^ :]+)\s*:\s*(.*)$/, rxJSHintValueSeparator = /\s*,\s*/; /** * Displays dialog with JSHint options. */ function showOptionsDialog() { var currentDoc = DocumentManager.getCurrentDocument(), opts = [], promise, dialog, dialogOkBtn, varEls, varLen, inputs, inputsLen, result, i, helpers = { toggleResultRollover: function (enabled) { var modalFooter = dialog.find('.modal-footer.first'); if (enabled === true) { modalFooter.addClass('rollover'); } else if (enabled === false) { modalFooter.removeClass('rollover'); } }, toggleCheckbox: function (checkbox, checked) { var jsonInput = dialog.find(checkbox); jsonInput.attr('checked', checked); } }; /** * Clears all dialog's options. */ function clearOptions() { varEls.val('default'). // Reset all var elements. removeClass('true false other'); inputs.val(''); // Clear input elements' values. result.val(''); // Clear the directive textarea. opts = []; // Empty options array. helpers.toggleResultRollover(false); // Disables rollover on textarea. } /** * Generates JSHint Directive. */ function generateDirective() { var optionName, optionValue, varElement; opts = []; // Empty options array. // Loop through all var element. for (i = 0; i < varLen; i += 1) { varElement = varEls[i]; if ($(varElement).val() !== 'default') { optionName = $(varElement).parent().attr('data-name'); optionValue = $(varElement).val(); opts.push(optionName + ': ' + optionValue); } } // Loop through all input elements. for (i = 0; i < inputsLen; i += 1) { if ($(inputs[i]).val() !== '') { optionName = $(inputs[i]).attr('data-name'); optionValue = $(inputs[i]).val(); opts.push(optionName + ': ' + optionValue); } } if (opts.length >= 1) { // If options array is NOT empty... result.val('/*jshint ' + opts.join(', ') + '*/'); // ...display the options as string in results placeholder. helpers.toggleResultRollover(true); // Enbles rollover on textarea. } else { // If options array is empty... result.val(''); // ...empty the results placeholder. helpers.toggleResultRollover(false); // Disables rollover on textarea. } } /** * Generates JSON string out of options selected. */ function generateJsonString() { var i = 0, parsedData = {}, jsonString, val; for (i; i < opts.length; i += 1) { val = opts[i].substr(opts[i].indexOf(':') + 2); if (val === 'true') { parsedData[opts[i].substr(0, opts[i].indexOf(':'))] = true; } else if (val === 'false') { parsedData[opts[i].substr(0, opts[i].indexOf(':'))] = false; } else if (!isNaN(val)) { parsedData[opts[i].substr(0, opts[i].indexOf(':'))] = +val; } else if (typeof val === 'string') { parsedData[opts[i].substr(0, opts[i].indexOf(':'))] = val; } } jsonString = JSON.stringify(parsedData, null, '\t'); result.val(jsonString); } /** * Inserts JSHint directive on editor body. */ function insertDirectiveToEditor() { var editor = EditorManager.getCurrentFullEditor(), editorDoc = editor.document, startPosition = {line: 0, ch: 0}, firstLineContent = currentDoc.getLine(0); editor.setCursorPos(startPosition); // Set cursor to line 0 and column 0. editorDoc.replaceRange(result.val() + '\n', startPosition); // Insert directive at first line and push document one line down. // Check if document already has a JSLint directive // and remove the line with the old directive. if (rxJSHintOptions.test(firstLineContent)) { editorDoc.replaceRange('', {line: 1, ch: 0}, {line: 2, ch: 0}); } } /** * Gets directive from editor and populates the appropriate options in dialog. * @param directiveString {String} The directive string, taken either from editor or the config file. */ function populateModalOptions(directiveString) { var tempArr = [], arr = [], arrLen, tempStr, arrItem, i; tempStr = (directiveString.match(rxJSHintOptions) || []).pop(); if (tempStr) arr = tempStr.split(rxJSHintValueSeparator).map(function (value) { var option = value.match(rxJSHintValue); if (option) return { name: option[1], value: option[2] }; }); arrLen = arr.length; for (i = 0; i < arrLen; i += 1) { arrItem = arr[i]; if (arrItem) { // Update the dialog's options only if the values specified are valid (true or false). if (arrItem.value === 'true' || arrItem.value === 'false') { dialog.find('.modal-body div[data-name="' + arrItem.name + '"] select'). val(arrItem.value). addClass(arrItem.value); } if (arrItem.value !== 'true' && arrItem.value !== 'false' && arrItem.value !== 'default') { dialog.find('.modal-body div[data-name="' + arrItem.name + '"] select'). val(arrItem.value). addClass('other'); } if (!isNaN(arrItem.value)) { dialog.find('.modal-body input[data-name="' + arrItem.name + '"]').val(arrItem.value); } } } generateDirective(); } /** * Creates a new untitled file and appends content. */ function openFile(content, fileExtension) { var counter = 1, doc = DocumentManager.createUntitledDocument(counter, fileExtension); doc.setText(content); } /** * Disables Dialog's OK button. */ function disableDialogOkButton() { dialogOkBtn. attr('disabled', true). prop('disabled', true); } /** * Enables Dialog's OK button. */ function enableDialogOkButton() { dialogOkBtn. attr('disabled', false). prop('disabled', false); } promise = Dialogs.showModalDialogUsingTemplate(Mustache.render(OptionsTemplate, Strings)). done(function (id) { // if button OK clicked... if (id === Dialogs.DIALOG_BTN_OK) { if (opts.length >= 1) { insertDirectiveToEditor(); dialog.off('click'); dialog.off('change'); } } // if button CANCEL clicked... if (id === Dialogs.DIALOG_BTN_CANCEL) { dialog.off('click'); dialog.off('change'); } }); dialog = $('.georapbox-jshint-settings-dialog.instance'); // dialog modal dialogOkBtn = dialog.find('a[data-button-id="ok"]'); // dialog OK button varEls = dialog.find('.modal-body').find('select'); // dialog dropdowns varLen = varEls.length; // dialog dropdowns length inputs = dialog.find('.modal-body').find('input[type="number"]'); // dialog inputs inputsLen = inputs.length; // inputs length result = dialog.find('#georapbox-jsl-conf-result'); // result placeholder // Populate modal options based on directive derived from current docuent or configuration file. // If directive is derived from document, assumes that directive will be found in first line of current document. if (rxJSHintOptions.test(currentDoc.getLine(0))) { populateModalOptions(currentDoc.getLine(0)); } else { JSHintConfig.getDirective().then(function (directiveStr) { populateModalOptions(directiveStr); }); } if (FileExtension.get() !== 'js') { disableDialogOkButton(); } // Add event handlers. dialog. on('change', '.modal-body select', function () { var self = $(this); switch (self.val()) { case 'true': self.removeClass('false other').addClass('true'); break; case 'false': self.removeClass('true other').addClass('false'); break; case 'default': self.removeClass('true false other'); break; default: self.removeClass('default true false').addClass('other'); break; } if ($(this).val() === 'true') { $(this).addClass('true'); } helpers.toggleCheckbox('input[name="jsonConvert"]', false); generateDirective(); }). on('click', '.modal-header a.clear-options', function () { clearOptions(); helpers.toggleCheckbox('input[name="jsonConvert"]', false); if (FileExtension.get() === 'js') { enableDialogOkButton(); } }). on('click', '.modal-footer .select-button', function () { result.focus(); result.select(); }). on('click', '.modal-footer .extract-button', function () { var jsonConverter = dialog.find('input[name="jsonConvert"]'), textareaVal = result.val(), extractedFileExtension; // Check if directive value is empty. if (textareaVal.trim() === '') { return; } // Close JSHint options dialog. Dialogs.cancelModalDialogIfOpen('georapbox-jshint-settings-dialog'); // Determine file extension. if (jsonConverter.is(':checked')) { extractedFileExtension = '.json'; } else { extractedFileExtension = '.txt'; } // Create a new untitled file with the appropriate extension. openFile(textareaVal, extractedFileExtension); }). on('change', '.modal-body input[type="number"]', function () { generateDirective(); helpers.toggleCheckbox('input[name="jsonConvert"]', false); }). on('change', '.modal-footer input[name="jsonConvert"]', function () { var textareaVal = result.val(); if (textareaVal.trim() !== '') { if ($(this).is(':checked')) { generateJsonString(); disableDialogOkButton(); } else { generateDirective(); if (FileExtension.get() === 'js') { enableDialogOkButton(); } } } }); return promise; } exports.show = showOptionsDialog; });