See #260 - adds UI for changing optimization settings.
authorJakub Pawlowicz <contact@jakubpawlowicz.com>
Tue, 1 Nov 2016 07:56:21 +0000 (08:56 +0100)
committerJakub Pawlowicz <contact@jakubpawlowicz.com>
Thu, 3 Nov 2016 19:06:21 +0000 (20:06 +0100)
Note: it disables advanced optimizations by default.

Why:

* To give users better control over how optimizations are applied.

docs/css/home.css
docs/img/gear.svg [new file with mode: 0644]
docs/index.html
docs/js/drag-drop.js
docs/js/optimizer-worker.js
docs/js/optimizer.js
docs/js/settings.js [new file with mode: 0644]

index b9db024..79bc441 100644 (file)
@@ -17,6 +17,10 @@ a, article, body, div, fieldset, form, h1, h2, h3, h4, h5, h6, input, label, li,
   margin-top: 0;
 }
 
+select {
+  font-size: 16px;
+}
+
 .logo__link {
   background: url(../img/logo.svg) no-repeat center 55%;
   display: block;
@@ -35,25 +39,26 @@ a, article, body, div, fieldset, form, h1, h2, h3, h4, h5, h6, input, label, li,
 .drag-target {
   border: 5px dashed hsl(0, 0%, 90%);
   margin-bottom: 2rem;
+  padding: 1rem;
+  position: relative;
+}
+
+.dropped-files {
+  list-style: none;
   min-height: 10rem;
 }
 
-.drag-target:empty:before {
+.dropped-files:empty:before {
   content: attr(title);
   color: hsl(0, 0%, 15%);
   display: block;
   font-weight: bold;
-  height: inherit;
-  padding-top: 3rem;
+  height: 10rem;
+  line-height: 12rem;
   text-align: center;
   text-transform: uppercase;
 }
 
-.dropped-files {
-  list-style: none;
-  padding: 1rem;
-}
-
 .dropped-files__file {
   padding: 0.25rem 0.5rem;
 }
@@ -97,6 +102,81 @@ a, article, body, div, fieldset, form, h1, h2, h3, h4, h5, h6, input, label, li,
   margin-left: 0.5rem;
 }
 
+.settings:not(.settings--collapsed) {
+  border-top: 3px solid hsl(0, 0%, 90%);
+  margin-top: 2rem;
+  padding: 1rem 0 0;
+}
+
+.settings--collapsed {
+  cursor: pointer;
+  height: 1rem;
+}
+
+.settings--collapsed:before {
+  background: url(../img/gear.svg) center center no-repeat;
+  bottom: 1rem;
+  content: " ";
+  display: block;
+  height: 1.5rem;
+  right: 1rem;
+  position: absolute;
+  width: 1.5rem;
+}
+
+.settings--collapsed > .settings__group {
+  display: none;
+}
+
+.settings__group {
+  border: none;
+}
+
+.settings__group {
+  padding: 0.25rem 0 0.25rem 0.75rem;
+}
+
+.settings__group:not(:last-child) {
+  border-left: 0.25rem solid hsl(198, 76%, 52%);
+  margin-bottom: 0.5rem;
+}
+
+.settings__group__wrapper:not(:last-child) {
+  margin-bottom: 0.25rem;
+}
+
+.settings__option--version {
+  width: 100%;
+}
+
+.settings__option--checkbox {
+  vertical-align: 1px;
+}
+
+.settings__option--checkbox:disabled + .settings__label {
+  color: hsl(0, 0%, 40%);
+}
+
+.settings__option--precision {
+  text-align: center;
+  width: 2.5rem;
+}
+
+.settings__option--compatibility {
+  width: 100%;
+}
+
+.settings__option--keep-special-comments {
+  width: 100%;
+}
+
+.settings__option--apply {
+  background: transparent;
+  border: 1px solid hsl(0, 0%, 80%);
+  float: right;
+  padding: 0.5rem 1rem;
+}
+
 .clipboard-copy {
   border: none;
   height: 2rem;
diff --git a/docs/img/gear.svg b/docs/img/gear.svg
new file mode 100644 (file)
index 0000000..0fdc317
--- /dev/null
@@ -0,0 +1,7 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px" height="24px" viewBox="0 0 24 24"><g >
+<path fill="#343434" d="M23,14v-4h-3.262c-0.189-0.732-0.477-1.422-0.852-2.058l2.306-2.306l-2.828-2.828l-2.306,2.306
+C15.422,4.739,14.732,4.451,14,4.262V1h-4v3.262C9.268,4.451,8.578,4.739,7.942,5.114L5.636,2.808L2.808,5.636l2.306,2.306
+C4.739,8.578,4.451,9.268,4.262,10H1v4h3.262c0.189,0.732,0.477,1.422,0.852,2.058l-2.306,2.306l2.828,2.828l2.306-2.306
+c0.635,0.375,1.326,0.663,2.058,0.852V23h4v-3.262c0.732-0.189,1.422-0.477,2.058-0.852l2.306,2.306l2.828-2.828l-2.306-2.306
+c0.375-0.635,0.663-1.326,0.852-2.058H23z M12,15c-1.657,0-3-1.343-3-3s1.343-3,3-3s3,1.343,3,3S13.657,15,12,15z"/>
+</g></svg>
\ No newline at end of file
index fe67f79..0e27e89 100644 (file)
@@ -7,13 +7,72 @@
   <link rel="stylesheet" type="text/css" href="css/home.css"/>
   <script src="js/optimizer.js"></script>
   <script src="js/drag-drop.js"></script>
+  <script src="js/settings.js"></script>
 </head>
 <body>
   <h1 class="logo">
     <a class="logo__link" href="//github.com/jakubpawlowicz/clean-css" title="Go to clean-css project page">Go to clean-css project page</a>
   </h1>
   <article class="content">
-    <ol class="drag-target dropped-files" title="Drop your files here to optimize them"></ol>
+    <section class="drag-target">
+      <ol class="dropped-files" title="Drop your files here to optimize them"></ol>
+      <form class="settings settings--collapsed">
+        <fieldset class="settings__group">
+          <select class="settings__option settings__option--version" name="version">
+            <option value="v3.4.20" selected>3.4.20 (latest)</option>
+          </select>
+        </fieldset>
+        <fieldset class="settings__group settings__group--advanced">
+          <div class="settings__group__wrapper">
+            <input class="settings__option settings__option--checkbox settings__option--advanced" type="checkbox" id="advanced" name="advanced" />
+            <label class="settings__label" for="advanced">advanced optimizations</label>
+          </div>
+          <div class="settings__group__wrapper">
+            <input class="settings__option settings__option--checkbox" type="checkbox" id="aggressive_merging" name="aggressive-merging" disabled />
+            <label class="settings__label" for="aggressive_merging">aggressive merging</label>
+          </div>
+          <div class="settings__group__wrapper">
+            <input class="settings__option settings__option--checkbox" type="checkbox" id="media_merging" name="media-merging" disabled />
+            <label class="settings__label" for="media_merging">@media merging</label>
+          </div>
+          <div class="settings__group__wrapper">
+            <input class="settings__option settings__option--checkbox" type="checkbox" id="restructuring" name="restructuring" disabled />
+            <label class="settings__label" for="restructuring">restructuring</label>
+          </div>
+          <div class="settings__group__wrapper">
+            <input class="settings__option settings__option--checkbox" type="checkbox" id="shorthand_compacting" name="shorthand-compacting" disabled />
+            <label class="settings__label" for="shorthand_compacting">shorthand compacting</label>
+          </div>
+        </fieldset>
+        <fieldset class="settings__group">
+          <div class="settings__group__wrapper">
+            <input class="settings__option" type="checkbox" id="keep_breaks" name="keep-breaks" checked />
+            <label class="settings__label" for="keep_breaks">keep line breaks</label>
+          </div>
+          <div class="settings__group__wrapper">
+            <input class="settings__option settings__option--precision" type="number" min="-1" max="999999" id="rounding_precision" name="rounding-precision" value="2" />
+            <label class="settings__label" for="rounding_precision">rounding precision</label>
+          </div>
+          <div class="settings__group__wrapper">
+            <select class="settings__option settings__option--compatibility" id="compatibility" name="compatibility">
+              <option value="" selected>Modern browsers compatibility</option>
+              <option value="ie8">Modern browsers &amp; Internet Explorer 8 compatibility</option>
+              <option value="ie7">Modern browsers &amp; Internet Explorer 7/8 compatibility</option>
+            </select>
+          </div>
+          <div class="settings__group__wrapper">
+            <select class="settings__option settings__option--keep-special-comments" id="keep_special_comments" name="keep-special-comments">
+              <option value="*" selected>Keep all special comments</option>
+              <option value="1">Remove all special but one special comment</option>
+              <option value="0">Remove all special comments</option>
+            </select>
+          </div>
+        </fieldset>
+        <fieldset class="settings__group">
+          <input class="settings__option settings__option--apply" type="button" name="" value="Apply"/>
+        </fieldset>
+      </form>
+    </section>
     <p class="legend">
       CSS optimizing happens directly in your browser using a browser-compatible build of clean-css. If you miss any functionality, you are more than welcome to <a href="//github.com/jakubpawlowicz/clean-css/tree/master/docs">add it</a>!
     </p>
index 9c2111a..db157af 100644 (file)
 
   window.addEventListener('DOMContentLoaded', function () {
     var dragTarget = document.querySelector('.drag-target')
+    var dropContainer = document.querySelector('.dropped-files')
 
     dragTarget.addEventListener('dragenter', fileDraggedIn, false)
     dragTarget.addEventListener('dragover', fileDraggedOver, false)
-    dragTarget.addEventListener('drop', fileDropped(dragTarget), false)
+    dragTarget.addEventListener('drop', fileDropped(dropContainer), false)
 
     Optimizer.oncomplete = optimizationCompleted
   })
index 83fae5f..3fc880d 100644 (file)
@@ -4,7 +4,7 @@ onmessage = function(event) {
 
   switch (event.data.command) {
     case 'optimize':
-      new CleanCSS().minify(event.data.input, function (error, output) {
+      new CleanCSS(event.data.options).minify(event.data.input, function (error, output) {
         postMessage({
           command: 'optimized',
           id: event.data.id,
index d379803..b6460f3 100644 (file)
@@ -1,4 +1,6 @@
 Optimizer = {
+  options: null, // see setOptionsFrom in settings.js
+
   start: function () {
     this.worker = new Worker('./js/optimizer-worker.js')
     this.worker.onmessage = function (event) {
@@ -16,7 +18,8 @@ Optimizer = {
     this.worker.postMessage({
       command: 'optimize',
       id: id,
-      input: styles
+      input: styles,
+      options: this.options
     })
   },
 
diff --git a/docs/js/settings.js b/docs/js/settings.js
new file mode 100644 (file)
index 0000000..7e200f2
--- /dev/null
@@ -0,0 +1,70 @@
+(function () {
+  function show(settingsForm) {
+    return function (event) {
+      if (event.target.classList.contains('settings__option--apply'))
+        return
+
+      if (settingsForm.classList.contains('settings--collapsed')) {
+        event.preventDefault()
+        settingsForm.classList.remove('settings--collapsed')
+      }
+    }
+  }
+
+  function hide(settingsForm) {
+    return function (event) {
+      event.preventDefault()
+      settingsForm.classList.add('settings--collapsed')
+    }
+  }
+
+  function setOptionsFrom(settingsForm) {
+    return function () {
+      Optimizer.options = {
+        advanced: settingsForm.querySelector('[name=advanced]').checked,
+        aggressiveMerging: settingsForm.querySelector('[name=aggressive-merging]').checked,
+        compatibility: settingsForm.querySelector('[name=compatibility]').value,
+        keepBreaks: settingsForm.querySelector('[name=keep-breaks]').checked,
+        keepSpecialComments: keepSpecialCommentsFrom(settingsForm.querySelector('[name=keep-special-comments]').value),
+        mediaMerging: settingsForm.querySelector('[name=media-merging]').checked,
+        processImport: false,
+        rebase: false,
+        restructuring: settingsForm.querySelector('[name=restructuring]').checked,
+        roundingPrecision: parseInt(settingsForm.querySelector('[name=rounding-precision]').value),
+        shorthandCompacting: settingsForm.querySelector('[name=shorthand-compacting]').checked
+      }
+    }
+  }
+
+  function keepSpecialCommentsFrom(value) {
+    if (/^\d+$/.test(value)) {
+      return parseInt(value)
+    } else {
+      return value
+    }
+  }
+
+  function toggleAdvancedOptionsIn(settingsForm) {
+    var checkboxNodes = settingsForm.querySelectorAll('.settings__group--advanced .settings__option--checkbox')
+
+    return function () {
+      Array.prototype.slice.call(checkboxNodes, 1).forEach(function (node) {
+        node.disabled = !node.disabled
+        node.checked = !node.checked
+      })
+    }
+  }
+
+  window.addEventListener('DOMContentLoaded', function () {
+    var settingsForm = document.querySelector('.settings')
+    var applySettingsButton = settingsForm.querySelector('.settings__option--apply')
+    var advancedOptionNode = settingsForm.querySelector('.settings__option--advanced')
+
+    settingsForm.addEventListener('click', show(settingsForm), false)
+    applySettingsButton.addEventListener('click', hide(settingsForm), false)
+    applySettingsButton.addEventListener('click', setOptionsFrom(settingsForm), false)
+    advancedOptionNode.addEventListener('click', toggleAdvancedOptionsIn(settingsForm), false)
+
+    setOptionsFrom(settingsForm)()
+  })
+})()