diff --git a/components/autocomplete/init.js b/components/autocomplete/init.js deleted file mode 100755 index 1b77d51..0000000 --- a/components/autocomplete/init.js +++ /dev/null @@ -1,696 +0,0 @@ -/* - * Copyright (c) Codiad & Kent Safranski (codiad.com), distributed - * as-is and without warranty under the MIT License. See - * [root]/license.txt for more. This information must remain intact. - */ - -(function (global, $) { - - var EventEmitter = ace.require('ace/lib/event_emitter').EventEmitter; - var Range = ace.require('ace/range').Range; - - - var codiad = global.codiad; - - $(function () { - codiad.autocomplete.init(); - }); - - ////////////////////////////////////////////////////////////////// - // - // Autocomplete Component for Codiad - // --------------------------------- - // Show a popup with word completion suggestions. - // - ////////////////////////////////////////////////////////////////// - - codiad.autocomplete = { - - wordRegex: /[^a-zA-Z_0-9\$]+/, - - isVisible: false, - - standardGoLineDownExec: null, - - standardGoLineUpExec: null, - - _suggestionCache: null, - - standardGoToRightExec: null, - - standardGoToLeftExec: null, - - standardIndentExec: null, - - init: function () { - var _this = this; - - this.$onDocumentChange = this.onDocumentChange.bind(this); - this.$selectNextSuggestion = this.selectNextSuggestion.bind(this); - this.$selectPreviousSuggestion = this.selectPreviousSuggestion.bind(this); - this.$complete = this.complete.bind(this); - this.$hide = this.hide.bind(this); - - /* Catch click on suggestion */ - $('#autocomplete li').live('click', function () { - $('#autocomplete li.active-suggestion').removeClass('active-suggestion'); - $(this).addClass('active-suggestion'); - _this.complete(); - }); - - /* In debug mode, run some tests here. */ - // this._testSimpleMatchScorer(); - // this._testFuzzyMatcher(); - }, - - suggest: function () { - var _this = this; - - var cursorPosition = this._getEditor().getCursorPosition(); - var foundSuggestions = this.updateSuggestions(cursorPosition); - if (foundSuggestions) { - this.addListenerToOnDocumentChange(); - - // Show the completion popup. - this.show(); - - // handle click-out autoclosing. - var fn = function ( event ) { - let keycodes = [ 9, 10, 13 ] - - /*if( ! keycodes.includes( event.keyCode ) ) { - return; - }*/ - _this.hide(); - $(window).off('click', fn); - }; - $(window).on('click', fn); - } else { - this.clearSuggestionCache(); - } - }, - - /* Update the suggestions for the word at the given position. Return true if - * some suitable suggestions could be found, false if not. */ - updateSuggestions: function (position) { - var _this = this; - - var session = this._getEditSession(); - - /* Extract the word being typed. Keep only the part of the word - * which is before the given position. It is somehow the prefix of - * the wanted full word. Make sure we only keep one word. */ - var token = session.getTokenAt(position.row, position.column); - if (!token) { - /* No word at the given position. */ - this.removeSuggestions(); - return false; - } - - var prefix = token.value.substr(0, position.column - token.start); - prefix = prefix.split(this.wordRegex).slice(-1)[0]; - if (prefix === '') { - /* No word at the given position. */ - this.removeSuggestions(); - return false; - } - - /* Build and order the suggestions themselves. */ - // TODO cache suggestions and augment them incrementally. - var suggestionsAndDistance = this.getSuggestions(position); - var suggestions = this.rankSuggestions(prefix, suggestionsAndDistance); - if (suggestions.length < 1) { - /* No suitable suggestions found. */ - this.removeSuggestions(); - return false; - } - - /* Remove the existing suggestions and populate the popup with the - * updated ones. */ - this.removeSuggestions(); - var popupContent = $('#autocomplete #suggestions'); - $.each(suggestions, function (index, suggestion) { - /* First get rid of the suggestion suffix. */ - suggestion = suggestion.slice(0, -1); - - var indexes = _this.getMatchIndexes(prefix, suggestion); - $.each(indexes.reverse(), function (index, matchIndex) { - suggestion = suggestion.substr(0, matchIndex) + - '' + - suggestion.substr(matchIndex, 1) + - '' + - suggestion.substr(matchIndex + 1); - }); - popupContent.append('
  • ' + suggestion + '
  • '); - }); - - this.selectFirstSuggestion(); - - return true; - }, - - show: function () { - this.isVisible = true; - - var popup = $('#autocomplete'); - popup.css({ - 'top': this._computeTopOffset(), - 'left': this._computeLeftOffset(), - 'font-family': $('.ace_editor').css('font-family'), - 'font-size': $('.ace_editor').css('font-size') - }); - popup.slideToggle('fast', function(){ - $(this).css('overflow', ''); - }); - - this.addKeyboardCommands(); - }, - - hide: function () { - this.isVisible = false; - - $('#autocomplete').hide(); - this.removeSuggestions(); - this.clearSuggestionCache(); - - this.removeListenerToOnDocumentChange(); - this.removeKeyboardCommands(); - }, - - /* Return a jQuery object containing the currently selected suggestion. */ - getSelectedSuggestion: function () { - var selectedSuggestion = $('#autocomplete li.suggestion.active-suggestion'); - - if (selectedSuggestion.length < 1) { - alert(i18n('No suggestion selected. Might be a bug.')); - } else if (selectedSuggestion.length > 1) { - alert(i18n('More than one suggestions selected. Might be a bug.')); - } - - return selectedSuggestion; - }, - - selectFirstSuggestion: function () { - var firstChild = $('li.suggestion:first-child'); - firstChild.addClass('active-suggestion'); - this._ensureVisible(firstChild, $('#autocomplete')); - }, - - selectLastSuggestion: function () { - var lastChild = $('li.suggestion:last-child'); - lastChild.addClass('active-suggestion'); - this._ensureVisible(lastChild, $('#autocomplete')); - }, - - selectNextSuggestion: function () { - var selectedSuggestion = this.getSelectedSuggestion(); - selectedSuggestion.removeClass('active-suggestion'); - var nextSuggestion = selectedSuggestion.next(); - if (nextSuggestion.length > 0) { - nextSuggestion.addClass('active-suggestion'); - this._ensureVisible(nextSuggestion, $('#autocomplete')); - } else { - /* The currently selected suggestion is the last one. - * Go back to first one. */ - this.selectFirstSuggestion(); - } - }, - - selectPreviousSuggestion: function () { - var selectedSuggestion = this.getSelectedSuggestion(); - selectedSuggestion.removeClass('active-suggestion'); - var previousSuggestion = selectedSuggestion.prev(); - if (previousSuggestion.length > 0) { - previousSuggestion.addClass('active-suggestion'); - this._ensureVisible(previousSuggestion, $('#autocomplete')); - } else { - /* The currently selected suggestion is the first one. - * Go back to last one. */ - this.selectLastSuggestion(); - } - }, - - addListenerToOnDocumentChange: function () { - var session = this._getEditSession(); - session.addEventListener('change', this.$onDocumentChange); - }, - - removeListenerToOnDocumentChange: function () { - var session = this._getEditSession(); - session.removeEventListener('change', this.$onDocumentChange); - }, - - onDocumentChange: function (e) { - - if ( e.data === undefined || e.data === null || e.data.text.search(/^\s+$/) !== -1) { - this.hide(); - return; - } - - var position = null; - if (e.data.action === 'insertText') { - - if( codiad.autosave.saving === false ) { - position = e.data.range.end; - } else { - var start = new Date().getTime(); - for (var i = 0; i < 1e7; i++) { - if ((new Date().getTime() - start) > 50){ - break; - } - } - position = e.data.range.end; - } - } else if (e.data.action === 'removeText') { - position = e.data.range.start; - } else { - alert('Unkown document change action.'); - } - - var foundSuggestions = this.updateSuggestions(position); - if (!foundSuggestions) { - this.hide(); - } - }, - - addKeyboardCommands: function () { - var _this = this; - var commandManager = this._getEditor().commands; - - /* Save the standard commands that will be overwritten. */ - this.standardGoLineDownExec = commandManager.commands.golinedown.exec; - this.standardGoLineUpExec = commandManager.commands.golineup.exec; - - this.standardGoToRightExec = commandManager.commands.gotoright.exec; - this.standardGoToLeftExec = commandManager.commands.gotoleft.exec; - this.standardIndentExec = commandManager.commands.indent.exec; - - /* Overwrite with the completion specific implementations. */ - commandManager.commands.golinedown.exec = this.$selectNextSuggestion; - commandManager.commands.golineup.exec = this.$selectPreviousSuggestion; - - commandManager.commands.gotoright.exec = this.$complete; - commandManager.commands.gotoleft.exec = this.$hide; - commandManager.commands.indent.exec = this.$complete; - - commandManager.addCommand({ - name: 'hideautocomplete', - bindKey: 'Esc', - exec: function () { - _this.hide(); - } - }); - - commandManager.addCommand({ - name: 'autocomplete', - bindKey: 'Return', - exec: this.$complete - }); - }, - - removeKeyboardCommands: function () { - var commandManager = this._getEditor().commands; - - /* Make sure the standard exec have been initialized. */ - if (this.standardGoLineDownExec !== null) { - commandManager.commands.golinedown.exec = this.standardGoLineDownExec; - } - - if (this.standardGoLineUpExec !== null) { - commandManager.commands.golineup.exec = this.standardGoLineUpExec; - } - - if (this.standardGoToRightExec !== null) { - commandManager.commands.gotoright.exec = this.standardGoToRightExec; - } - - if (this.standardGoToLeftExec !== null) { - commandManager.commands.gotoleft.exec = this.standardGoToLeftExec; - } - - if (this.standardIndentExec !== null) { - commandManager.commands.indent.exec = this.standardIndentExec; - } - - commandManager.removeCommand('hideautocomplete'); - commandManager.removeCommand('autocomplete'); - }, - - /* Complete the word at the given position with the currently selected - * suggestion. Only the part of the word before the position is - * replaced. */ - complete: function (position) { - var editor = this._getEditor(); - var session = this._getEditSession(); - - var position = editor.getCursorPosition(); - - /* Get the length of the word being typed. */ - var token = session.getTokenAt(position.row, position.column); - if (!token) { - /* No token at the given position. */ - this.clearSuggestionCache(); - this.hide(); - editor.focus(); - } - - var prefix = token.value.substr(0, position.column - token.start); - var prefixLength = prefix.split(this.wordRegex).slice(-1)[0].length; - - var range = new Range(position.row, - position.column - prefixLength, - position.row, - position.column); - - var suggestion = this.getSelectedSuggestion().text(); - session.replace(range, suggestion); - - this.hide(); - editor.focus(); - }, - - /* Remove the suggestions from the Dom. */ - removeSuggestions: function () { - $('.suggestion').remove(); - }, - - /* Get suggestions of completion for the current position in the - * document. */ - getSuggestions: function (position) { - - /* If suggestions are cached, - * return them directely */ - if (this._suggestionCache) { - return this._suggestionCache; - } - - var doc = this._getDocument(); - - /* FIXME For now, make suggestions on the whole file content except - * the current token. Might be a little bit smarter, e.g., remove - * all the keywords associated with the current language. */ - - /* Get all the text, put a marker at the cursor position. The - * marker uses word character so that it won't be discarded by a - * word split. */ - var markerString = '__autocomplete_marker__'; - var text = doc.getLines(0, position.row - 1).join("\n") + "\n"; - var currentLine = doc.getLine(position.row); - text += currentLine.substr(0, position.column); - text += markerString; - if (position.column === currentLine.length) { - // position is at end of line, add a break line. - text += "\n"; - } - text += currentLine.substr(position.column + 1); - text += doc.getLines(position.row + 1, doc.getLength()).join("\n") + "\n"; - - /* Split the text into words. */ - var suggestions = text.split(this.wordRegex); - - /* Get the index of the word at the cursor position. */ - var markerIndex = 0; - var markedWord = ''; - $.each(suggestions, function (index, value) { - if (value.search(markerString) !== -1) { - markerIndex = index; - markedWord = value; - return false; - } - }); - - /* Build an object associating the suggestions with their distance - * to the word at cursor position. To make sure that no suggestion - * string overrides a built-in method of the suggestionsAndDistance - * object, suffix all the suggestions with '-'. Afterward, make - * sure of removing that suffix before using the stored - * suggestions! */ - var suggestionsAndDistance = {}; - $.each(suggestions, function (index, suggestion) { - var distance = Math.abs(index - markerIndex); - if (!suggestionsAndDistance[suggestion + '-'] || - distance < suggestionsAndDistance[suggestion]) { - suggestionsAndDistance[suggestion + '-'] = distance; - } - }); - - /* Remove from the suggestions the word under the cursor. */ - delete suggestionsAndDistance[markedWord + '-']; - - /* Fill the cache */ - this._suggestionCache = suggestionsAndDistance; - - return suggestionsAndDistance; - }, - - /* Clear the suggestion cache */ - clearSuggestionCache: function () { - this._suggestionCache = null; - }, - - /* Given an object associating suggestions and their distances to the - * word under the cursor (the prefix), return a ranked array of - * suggestions with the best match first. The suggestions are ranked - * based on if they match the prefix fuzzily, how much they match the - * given prefix in the computeSimpleMatchScore sense and on their - * distances to the prefix. */ - rankSuggestions: function (prefix, suggestionsAndDistance) { - /* Initialize maxScore to one to ensure removing the non matching - * suggestions (those with a zero score). */ - var maxScore = 1; - var suggestionsAndMatchScore = {}; - for (var suggestion in suggestionsAndDistance) { - if (Object.prototype.hasOwnProperty.call(suggestionsAndDistance, suggestion)) { - var score = this.computeSimpleMatchScore(prefix, suggestion); - if (score > maxScore) { - maxScore = score; - } - suggestionsAndMatchScore[suggestion] = score; - } - } - - /* Remove the suggestions that do not match the prefix fuzzily. */ - for (suggestion in suggestionsAndMatchScore) { - if (Object.prototype.hasOwnProperty.call(suggestionsAndMatchScore, suggestion)) { - if (!this.isMatchingFuzzily(prefix, suggestion)) { - delete suggestionsAndMatchScore[suggestion]; - } - } - } - - /* Now for each suggestion we have its matching score and its - * distance to the word under the cursor. So compute its final - * score as a combination of both. */ - var suggestionsAndFinalScore = {}; - for (suggestion in suggestionsAndMatchScore) { - if (Object.prototype.hasOwnProperty.call(suggestionsAndMatchScore, suggestion)) { - //suggestionsAndFinalScore[suggestion] = suggestionsAndMatchScore[suggestion] - - // suggestionsAndDistance[suggestion]; - suggestionsAndFinalScore[suggestion] = suggestionsAndMatchScore[suggestion] / suggestion.length; - } - } - - /* Make an array of suggestions and make sure to rank them in the - * ascending scores order. */ - var suggestions = []; - for (suggestion in suggestionsAndFinalScore) { - if (Object.prototype.hasOwnProperty.call(suggestionsAndFinalScore, suggestion)) { - suggestions.push(suggestion); - } - } - - suggestions.sort(function (firstSuggestion, secondSuggestion) { - return suggestionsAndFinalScore[secondSuggestion] - suggestionsAndFinalScore[firstSuggestion]; - }); - - return suggestions; - }, - - /* Return the number of consecutive letters starting from the first - * letter in suggestion that match prefix. For instance, - * this.computeSimpleMatchScore(cod, codiad) will return 3. If - * suggestion is shorter than prefix, return a score of zero. The score - * is computed using a Vim-like smartcase behavior. */ - computeSimpleMatchScore: function (prefix, suggestion) { - /* Use a Vim-like smartcase behavior. If prefix is all lowercase, - * compute the match score case insensitive, if it is not, compute - * the score case sensitive. */ - var localSuggestion = this._isLowerCase(prefix) ? suggestion.toLowerCase() : suggestion; - - if (localSuggestion.length < prefix.length) { - return 0; - } else if (localSuggestion === prefix) { - return prefix.length; - } else { - var score = 0; - for (var i = 0; i < prefix.length; ++i) { - if (localSuggestion[i] === prefix[i]) { - ++score; - } else { - break; - } - } - - return score; - } - }, - - /* Return true if suggestion fuzzily matches prefix. Because everybody - * loves fuzzy matches. - * For instance, this.isMatchingFuzzily(mlf, mylongfunctionname) - * will return true. The score is computed using a Vim-like smartcase - * behavior. */ - isMatchingFuzzily: function (prefix, suggestion) { - /* Use a Vim-like smartcase behavior. If prefix is all lowercase, - * compute the match score case insensitive, if it is not, compute - * the score case sensitive. */ - var localSuggestion = this._isLowerCase(prefix) ? suggestion.toLowerCase() : suggestion; - - /* Escape the characters that have a special meaning for regex in - * the prefix. */ - var localPrefix = prefix.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); - - var fuzzyRegex = '^.*?'; - for (var i = 0; i < localPrefix.length; ++i) { - if (localPrefix[i] === '\\') { - fuzzyRegex += localPrefix[i]; - ++i; - } - - fuzzyRegex += localPrefix[i]; - fuzzyRegex += '.*?'; - } - - if (localSuggestion.search(fuzzyRegex) !== -1) { - return true; - } else { - return false; - } - }, - - getMatchIndexes: function (prefix, suggestion) { - /* Use a Vim-like smartcase behavior. If prefix is all lowercase, - * find the match indexes case insensitive, if it is not, find them - * case sensitive. */ - var localSuggestion = this._isLowerCase(prefix) ? suggestion.toLowerCase() : suggestion; - - var matchIndexes = []; - var startIndex = 0; - for (var i = 0; i < prefix.length; ++i) { - var index = localSuggestion.indexOf(prefix[i], startIndex); - matchIndexes.push(index); - startIndex = index + 1; - } - - return matchIndexes; - }, - - _isLowerCase: function (str) { - return (str.toLowerCase() === str); - }, - - _ensureVisible: function (el, parent) { - var offset = 1; - var paneMin = parent.scrollTop(); - var paneMax = paneMin + parent.innerHeight(); - var itemMin = el.position().top + paneMin - offset; - var itemMax = itemMin + el.outerHeight() + 2*offset; - if (itemMax > paneMax) { - parent.stop().animate({ - scrollTop: itemMax - parent.innerHeight() - }, 100); - } else if (itemMin < paneMin) { - parent.stop().animate({ - scrollTop: itemMin - }, 100); - } - }, - - _computeTopOffset: function () { - /* FIXME How to handle multiple cursors? This seems to compute the - * offset using the position of the last created cursor. */ - var cursor = $('.ace_cursor'); - if (cursor.length > 0) { - var fontSize = codiad.editor.getActive().container.style.fontSize.replace('px', ''); - var interLine = 1.7; - cursor = $(cursor[0]); - var top = cursor.offset().top + fontSize * interLine; - return top; - } - }, - - _computeLeftOffset: function () { - /* FIXME How to handle multiple cursors? This seems to compute the - * offset using the position of the last created cursor. */ - var cursor = $('.ace_cursor'); - if (cursor.length > 0) { - cursor = $(cursor[0]); - var left = cursor.offset().left; - return left; - } - }, - - /* Set of helper methods to manipulate the editor. */ - _getEditor: function () { - return codiad.editor.getActive(); - }, - - _getEditSession: function () { - return codiad.editor.getActive().getSession(); - }, - - _getDocument: function () { - return codiad.editor.getActive().getSession().getDocument(); - }, - - /* Some unit tests. */ - //i don't need to translate this... this is just for testing things... - _testSimpleMatchScorer: function () { - var prefix = 'myprefix'; - var suggestion = 'myprefixisshort'; - var score = this.computeSimpleMatchScore(prefix, suggestion); - if (score !== 8) { - alert('_testSimpleMatchScorer lowercase test failed.'); - } - - prefix = 'MYPREFIX'; - suggestion = 'MYPREFIXISSHORT'; - score = this.computeSimpleMatchScore(prefix, suggestion); - if (score !== 8) { - alert('_testSimpleMatchScorer uppercase test failed.'); - } - - prefix = 'myPrefix'; - suggestion = 'myprefixisshort'; - score = this.computeSimpleMatchScore(prefix, suggestion); - if (score !== 2) { - alert('_testSimpleMatchScorer mixed case vs. lowercase test failed.'); - } - - prefix = 'myPrefixIs'; - suggestion = 'myPrefixIsShort'; - score = this.computeSimpleMatchScore(prefix, suggestion); - if (score !== 10) { - alert('_testSimpleMatchScorer mixed case test failed.'); - } - }, - - _testFuzzyMatcher: function () { - var isMatching = this.isMatchingFuzzily('mlf', 'mylongfunctionname'); - if (!isMatching) { - alert('_testFuzzyMatcher mlf vs. mylongfunctionname failed.'); - } - - isMatching = this.isMatchingFuzzily('mLn', 'myLongFunctionName'); - if (!isMatching) { - alert('_testFuzzyMatcher mLn vs. myLongFunctionName failed.'); - } - isMatching = this.isMatchingFuzzily('mLFuny', 'myLongFunctionName'); - if (isMatching) { - alert('_testFuzzyMatcher mLFuny. myLongFunctionName failed.'); - } - } - - }; - -})(this, jQuery); \ No newline at end of file diff --git a/components/autosave/init.js b/components/autosave/init.js index c0b6ef8..adce226 100755 --- a/components/autosave/init.js +++ b/components/autosave/init.js @@ -74,7 +74,10 @@ } }); - console.log( 'Auto save Enabled' ); + if( codiad.auto_save.verbose ) { + + console.log( 'Auto save Enabled' ); + } this.auto_save_trigger = setInterval( this.auto_save, 256 ); }, diff --git a/components/editor/init.js b/components/editor/init.js index aae9865..800dddc 100755 --- a/components/editor/init.js +++ b/components/editor/init.js @@ -11,7 +11,7 @@ var Editor = ace.require('ace/editor').Editor; var EditSession = ace.require('ace/edit_session').EditSession; var UndoManager = ace.require("ace/undomanager").UndoManager; - + // Editor modes that have been loaded var editorModes = {}; @@ -386,6 +386,7 @@ // Settings for Editor instances settings: { + autocomplete: false, theme: 'twilight', fontSize: '13px', printMargin: false, @@ -450,8 +451,19 @@ 'tabSize', 'theme', ]; + var bool_options = [ + 'autocomplete', + 'printMargin', + 'highlightLine', + 'indentGuides', + 'wrapMode', + 'rightSidebarTrigger', + 'fileManagerTrigger', + 'softTabs', + 'persistentModal', + ]; - $.each(options, async function( idx, key ) { + $.each( options, async function( idx, key ) { var localValue = await codiad.settings.get_option( 'codiad.editor.' + key ); if ( localValue !== null ) { @@ -460,8 +472,7 @@ } }); - $.each(['printMargin', 'highlightLine', 'indentGuides', 'wrapMode', 'rightSidebarTrigger', 'fileManagerTrigger', 'softTabs', 'persistentModal'], - async function(idx, key) { + $.each( bool_options, async function(idx, key) { var localValue = await codiad.settings.get_option( 'codiad.editor.' + key ); if (localValue === null) { return; @@ -495,6 +506,11 @@ this.setTabSize(this.settings.tabSize, i); this.setSoftTabs(this.settings.softTabs, i); this.setOverScroll(this.settings.overScroll, i); + i.setOptions({ + enableBasicAutocompletion: true, + enableSnippets: true, + enableLiveAutocompletion: this.settings.autocomplete + }); }, ////////////////////////////////////////////////////////////////// @@ -540,12 +556,13 @@ pContainer.setChild(idx, sc); } } - + + ace.require("ace/ext/language_tools"); var i = ace.edit(el[0]); var resizeEditor = function(){ i.resize(); }; - + if (sc) { i.splitContainer = sc; i.splitIdx = chIdx; @@ -1564,6 +1581,24 @@ //Database codiad.settings.update_option( 'codiad.editor.overScroll', s ); }, + + setLiveAutocomplete: function( s, i ) { + + if (i) { + i.setOptions({ + enableLiveAutocompletion: s + }); + } else { + this.settings.autocomplete = s; + this.forEach(function(i) { + i.setOptions({ + enableLiveAutocompletion: s + }); + }); + } + //Database + codiad.settings.update_option( 'codiad.editor.autocomplete', s ); + }, }; diff --git a/components/settings/dialog.php b/components/settings/dialog.php index 3595747..c0645e8 100755 --- a/components/settings/dialog.php +++ b/components/settings/dialog.php @@ -140,6 +140,10 @@ case "codiad.editor.overScroll": codiad.editor.setOverScroll(val); break; + case "codiad.editor.autocomplete": + var bool_val = (val == "true"); + codiad.editor.setLiveAutocomplete(bool_val) + break; } } diff --git a/components/settings/settings.editor.php b/components/settings/settings.editor.php index 6ce3955..581968b 100755 --- a/components/settings/settings.editor.php +++ b/components/settings/settings.editor.php @@ -185,4 +185,17 @@ + + + + + + + + + + diff --git a/index.php b/index.php index 11ea32d..3daea4c 100755 --- a/index.php +++ b/index.php @@ -417,11 +417,12 @@ if( defined( "SITE_NAME" ) && ! ( SITE_NAME === "" || SITE_NAME === null ) ) { +