diff options
-rw-r--r-- | css/redirector.css | 77 | ||||
-rw-r--r-- | js/redirect.js | 48 | ||||
-rw-r--r-- | js/redirectorpage.js | 176 | ||||
-rw-r--r-- | redirector.html | 4 |
4 files changed, 263 insertions, 42 deletions
diff --git a/css/redirector.css b/css/redirector.css index 34ecaa3..5ad77a3 100644 --- a/css/redirector.css +++ b/css/redirector.css @@ -258,6 +258,65 @@ a.disabled:hover, button[disabled]:hover { background:white !important; } +/* Toggle Grouping Checkbox */ +.toggle-container { + display: block; + position: absolute; + top: 8%; + right: 5%; + cursor: pointer; + font-size: 22px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.toggle-container input { + position: absolute; + opacity: 0; + cursor: pointer; + height: 0; + width: 0; +} + +.checkmark { + position: absolute; + height: 15px; + width: 15px; + background-color: #eee; +} + +.toggle-container:hover input ~ .checkmark { + background-color: #ccc; +} + +.toggle-container input:checked ~ .checkMarked { + background-color: #2196F3; +} + +.checkmark:after { + content: ""; + position: absolute; + display: none; +} + +.toggle-container input:checked ~ .checkMarked:after { + display: block; +} + +.toggle-container .checkMarked:after { + left: 4px; + top: -1px; + width: 4px; + height: 9px; + border: solid white; + border-width: 0 3px 3px 0; + -webkit-transform: rotate(45deg); + -ms-transform: rotate(45deg); + transform: rotate(45deg); +} + /* Popup form for deleting redirects */ #delete-redirect-form { @@ -312,8 +371,8 @@ a.disabled:hover, button[disabled]:hover { } .blur { - -webkit-filter:blur(3px); - filter:blur(3px); + -webkit-filter:blur(3px); + filter:blur(3px); } #edit-redirect-form { @@ -353,7 +412,7 @@ a.disabled:hover, button[disabled]:hover { .input-cell { padding-top:1px; -} +} .form-grid div input[type='text'] { width:510px; @@ -404,7 +463,7 @@ a.disabled:hover, button[disabled]:hover { } ::-moz-placeholder { /* Firefox 19+ */ - color: #c0c0c0; + color: #c0c0c0; } .advanced { @@ -509,10 +568,10 @@ footer small a:hover { .redirect-row:nth-child(odd) { background: rgb(31,32,35); - } + } .redirect-row:nth-child(even) { background: rgb(41,42,45); - } + } .btn { background-color: rgb(32,33,36); @@ -527,6 +586,10 @@ footer small a:hover { color: rgb(53,180,75); } + .toggle { + background-color: #ccc; + } + #message-box.success { background-color: rgb(53,203,75);; } @@ -590,7 +653,7 @@ footer small a:hover { } .example-result-error { - color:rgb(252,87,84) !important; + color:rgb(252,87,84) !important; } #edit-redirect-form input { diff --git a/js/redirect.js b/js/redirect.js index 4ad57d5..b902da2 100644 --- a/js/redirect.js +++ b/js/redirect.js @@ -27,7 +27,7 @@ Redirect.requestTypes = { Redirect.prototype = { - + //attributes description : '', exampleUrl : '', @@ -40,7 +40,8 @@ Redirect.prototype = { patternType : '', processMatches : 'noProcessing', disabled : false, - + grouped: false, + compile : function() { var incPattern = this._preparePattern(this.includePattern); @@ -65,7 +66,7 @@ Redirect.prototype = { && this.processMatches == redirect.processMatches && this.appliesTo.toString() == redirect.appliesTo.toString(); }, - + toObject : function() { return { description : this.description, @@ -79,6 +80,7 @@ Redirect.prototype = { patternType : this.patternType, processMatches : this.processMatches, disabled : this.disabled, + grouped: this.grouped, appliesTo : this.appliesTo.slice(0) }; }, @@ -87,10 +89,10 @@ Redirect.prototype = { if (!this._rxInclude) { this.compile(); } - var result = { - isMatch : false, - isExcludeMatch : false, - isDisabledMatch : false, + var result = { + isMatch : false, + isExcludeMatch : false, + isDisabledMatch : false, redirectTo : '', toString : function() { return JSON.stringify(this); } }; @@ -106,11 +108,11 @@ Redirect.prototype = { result.redirectTo = redirectTo; } } - return result; + return result; }, - + //Updates the .exampleResult field or the .error - //field depending on if the example url and patterns match + //field depending on if the example url and patterns match //and make a good redirect updateExampleResult : function() { @@ -171,25 +173,25 @@ Redirect.prototype = { isRegex: function() { return this.patternType == Redirect.REGEX; }, - + isWildcard : function() { - return this.patternType == Redirect.WILDCARD; + return this.patternType == Redirect.WILDCARD; }, test : function() { - return this.getMatch(this.exampleUrl); + return this.getMatch(this.exampleUrl); }, - //Private functions below + //Private functions below _rxInclude : null, _rxExclude : null, - + _preparePattern : function(pattern) { if (!pattern) { return null; } if (this.patternType == Redirect.REGEX) { - return pattern; + return pattern; } else { //Convert wildcard to regex pattern var converted = '^'; for (var i = 0; i < pattern.length; i++) { @@ -206,7 +208,7 @@ Redirect.prototype = { return converted; } }, - + _init : function(o) { o = o || {}; this.description = o.description || ''; @@ -240,7 +242,7 @@ Redirect.prototype = { get appliesToText() { return this.appliesTo.map(type => Redirect.requestTypes[type]).join(', '); }, - + get processMatchesExampleText() { let examples = { noProcessing : 'Use matches as they are', @@ -256,11 +258,11 @@ Redirect.prototype = { toString : function() { return JSON.stringify(this.toObject(), null, 2); }, - + _includeMatch : function(url) { if (!this._rxInclude) { return null; - } + } var matches = this._rxInclude.exec(url); if (!matches) { return null; @@ -285,12 +287,12 @@ Redirect.prototype = { this._rxInclude.lastIndex = 0; return resultUrl; }, - + _excludeMatch : function(url) { if (!this._rxExclude) { - return false; + return false; } - var shouldExclude = this._rxExclude.test(url); + var shouldExclude = this._rxExclude.test(url); this._rxExclude.lastIndex = 0; return shouldExclude; } diff --git a/js/redirectorpage.js b/js/redirectorpage.js index f82b0b7..84bfadf 100644 --- a/js/redirectorpage.js +++ b/js/redirectorpage.js @@ -23,7 +23,7 @@ function saveChanges() { } }); } - + function toggleSyncSetting() { chrome.runtime.sendMessage({type:"toggle-sync", isSyncEnabled: !options.isSyncEnabled}, function(response) { if(response.message === "sync-enabled"){ @@ -60,16 +60,16 @@ function renderRedirects() { } function renderSingleRedirect(node, redirect, index) { - + //Add extra props to help with rendering... if (index === 0) { redirect.$first = true; } if (index === REDIRECTS.length - 1) { redirect.$last = true; - } + } redirect.$index = index; - + dataBind(node, redirect); node.setAttribute('data-index', index); @@ -77,6 +77,12 @@ function renderSingleRedirect(node, redirect, index) { btn.setAttribute('data-index', index); } + let checkmark = node.querySelectorAll('.checkmark'); + + if(checkmark.length == 1) { + checkmark[0].setAttribute('data-index', index); + } + //Remove extra props... delete redirect.$first; delete redirect.$last; @@ -117,19 +123,156 @@ function toggleDisabled(index) { saveChanges(); } +// function handleGroupedMove(index) { +// console.log(`NSC`, arguments); +// let grouping = REDIRECTS.filter(row => row.grouped); +// let size = grouping.length; +// console.log(grouping) +// } + +// function wrap(node, elm) { +// node.parentNode.insertBefore(elm, node); +// // node.previousElementSibling.appendChild(node); +// } + +function swap(node1, node2) { + const afterNode2 = node2.nextElementSibling; + const parent = node2.parentNode; + node1.replaceWith(node2); + parent.insertBefore(node1, afterNode2); +} + +function groupedMoveDown(group) { + // let grouping = REDIRECTS.map((row, i) => { return { row, index: i}}) + // .filter(result => result.row.grouped) + // .sort((a, b) => b.index - a.index); + for(let rule of group) { + // swap positions in dom + let elm = document.querySelector("[data-index='" + (rule.index).toString() + "']"); + let prev = document.querySelector("[data-index='" + (rule.index + group.length).toString() + "']"); + swap(elm,prev); + } + + for(let rule of group) { + // swap positions in array + rule.row.grouping = false; + let prevRedir = REDIRECTS[rule.index + group.length]; + REDIRECTS[rule.index + group.length] = REDIRECTS[rule.index]; + REDIRECTS[rule.index] = prevRedir; + // REDIRECTS[rule.index].grouped = false; + } +} + +function isGroupAdjacent(grouping) { + let distances = []; + for(let i = grouping.length - 1; i >= 0; i--) { + + if(i != 0) { + distances.push(grouping[i].index - grouping[i - 1].index); + + } + + } + return distances.every(distance => distance === 1); +} + +function groupedMoveUp(group) { + + + console.log(group); + + // working config - sort of + // for(let rule of group) { + // // swap positions in dom + // let elm = document.querySelector("[data-index='" + (rule.index).toString() + "']"); + // let prev = document.querySelector("[data-index='" + (rule.index - group.length).toString() + "']"); + // elm.childNodes[7].childNodes[3].classList.remove("checkMarked"); + // console.log(`NSC: groupedMoveUp -> elm`, elm); + // prev.childNodes[7].childNodes[3].classList.remove("checkMarked"); + // console.log(`NSC: groupedMoveUp -> prev`, prev); + // swap(elm,prev); + // } + + // for(let rule of group) { + // // swap positions in array + // rule.row.grouping = false; + // let prevRedir = REDIRECTS[rule.index - group.length]; + // REDIRECTS[rule.index - group.length] = REDIRECTS[rule.index]; + // REDIRECTS[rule.index] = prevRedir; + // // REDIRECTS[rule.index].grouped = false; + // } + + // only set the below to 1 if groupings are not next to each other. + var jumpLength = 1; + + if(isGroupAdjacent(group)) { + console.log('adjacent') + jumpLength = group.length; + } + + + + for(let rule of group) { + console.log(`NSC: groupedMoveUp -> rule`, rule); + // swap positions in dom + let elm = document.querySelector("[data-index='" + (rule.index).toString() + "']"); + console.log(`NSC: groupedMoveUp -> elm`, elm); + let prev = document.querySelector("[data-index='" + (rule.index - jumpLength).toString() + "']"); + console.log(`NSC: groupedMoveUp -> prev`, prev); + elm.childNodes[7].childNodes[3].classList.remove("checkMarked"); + prev.childNodes[7].childNodes[3].classList.remove("checkMarked"); + if(jumpLength > 1) { + swap(elm,prev); + } + + } + + for(let rule of group) { + // swap positions in array + rule.row.grouping = false; + let prevRedir = REDIRECTS[rule.index - jumpLength]; + REDIRECTS[rule.index - jumpLength] = REDIRECTS[rule.index]; + REDIRECTS[rule.index] = prevRedir; + } +} function moveUp(index) { - let prev = REDIRECTS[index-1]; - REDIRECTS[index-1] = REDIRECTS[index]; - REDIRECTS[index] = prev; + let grouping = REDIRECTS.map((row, i) => { return { row, index: i}}) + .filter(result => result.row.grouped) + .sort((a, b) => a.index - b.index); + + if(grouping.length > 1) { + // many + console.log('many') + + groupedMoveUp(grouping); + + } else { + // one + let prev = REDIRECTS[index-1]; + REDIRECTS[index-1] = REDIRECTS[index]; + REDIRECTS[index] = prev; + } + updateBindings(); saveChanges(); } function moveDown(index) { - let next = REDIRECTS[index+1]; - REDIRECTS[index+1] = REDIRECTS[index]; - REDIRECTS[index] = next; + let grouping = REDIRECTS.map((row, i) => { return { row, index: i}}) + .filter(result => result.row.grouped) + .sort((a, b) => a.index - b.index); + + if(grouping.length > 1) { + // many + groupedMoveDown(grouping); + } else { + // one + let next = REDIRECTS[index+1]; + REDIRECTS[index+1] = REDIRECTS[index]; + REDIRECTS[index] = next; + } + updateBindings(); saveChanges(); } @@ -138,7 +281,7 @@ function moveDown(index) { function pageLoad() { template = el('#redirect-row-template'); template.parentNode.removeChild(template); - + //Need to proxy this through the background page, because Firefox gives us dead objects //nonsense when accessing chrome.storage directly. chrome.runtime.sendMessage({type: "get-redirects"}, function(response) { @@ -169,7 +312,7 @@ function pageLoad() { )); } renderRedirects(); - }); + }); chrome.storage.local.get({isSyncEnabled:false}, function(obj){ options.isSyncEnabled = obj.isSyncEnabled; @@ -186,6 +329,11 @@ function pageLoad() { el('#storage-sync-option input').addEventListener('click', toggleSyncSetting); el('.redirect-rows').addEventListener('click', function(ev) { + // apply checkMarked class for Grouping + if(ev.target.type == 'checkbox') { + ev.target.nextElementSibling.classList.add("checkMarked"); + } + let action = ev.target.getAttribute('data-action'); //We clone and re-use nodes all the time, so instead of attaching and removing event handlers endlessly we just put @@ -214,4 +362,8 @@ let mql = window.matchMedia('(prefers-color-scheme:dark)'); mql.onchange = updateFavicon; updateFavicon(mql); +function toggleGrouping(index) { + REDIRECTS[index].grouped = !REDIRECTS[index].grouped; +} + pageLoad();
\ No newline at end of file diff --git a/redirector.html b/redirector.html index 078cabf..047a463 100644 --- a/redirector.html +++ b/redirector.html @@ -182,6 +182,10 @@ <button class="btn medium grey move-down-btn" data-action="moveDown" data-disabled="$last">▼</button> <button class="btn medium grey" data-action="duplicateRedirect">Duplicate</button> </div> + <label class="toggle-container"> + <input type="checkbox"> + <span class="checkmark" data-action="toggleGrouping"></span> + </label> </div> </div> <label id="storage-sync-option"><input type="checkbox" /> Enable Storage Sync</label> |