Hello Couchies,

I'd like to share another trick improving usability. Everybody comes across standard "<input type=dropdown>" when choose a folder for the article. Now, with DataBound we can CSS style this dropdown for Inline Edit using just regular tags. And also can style AdminEdit using a bunch of JS. This recipe took from me the whole day, and after thoroughly testing and optimizing I'm ready to share it.

First for the Inline. Let's create DataBound mode='edit' form and make a Radio-input. The options in this input represent the folders' structure of the template. We need to separate the folders with "|", but the last element should not have this separator (otherwise we have unwanted "<br>" tag). But Couch doesn't provide a tag "last_folder" for us, so I created a numeration "folder_number", so when this number equals "k_total_folders" the separator is not included.
Code: Select all
    <cms:form masterpage=k_template_name mode='edit' page_id=k_page_id method='post' anchor='0' >
       <cms:input type="radio" name="new_page_folderid" opt_values="
        <cms:set folder_number='0' />
        <cms:folders masterpage=k_template_name hierarchical="1">
         <cms:if k_folder_id=k_page_folderid>
          <b><cms:if k_folder_parentid!="-1" >- </cms:if><cms:show k_folder_title /></b> = <cms:show k_folder_id />
         <cms:else/>
          <span><cms:if k_folder_parentid!="-1" >- </cms:if><cms:show k_folder_title /></span> = <cms:show k_folder_id />
         </cms:if>
         <cms:set folder_number="<cms:add folder_number '1' />" />
         <cms:if folder_number!=k_total_folders>|</cms:if>
        </cms:folders>"
        opt_selected = "<cms:show k_page_folderid />"
        onchange="this.form.submit()"
       />
    </cms:form>

Next add a "Success" conditionals that rewrite Article's folder id into chosen one, and also refresh the page.
Code: Select all
    <cms:form masterpage=k_template_name mode='edit' page_id=k_page_id method='post' anchor='0' >
     <cms:if k_success >
      <cms:db_persist_form _invalidate_cache='0' k_page_folder_id=frm_new_page_folderid  />
      <cms:redirect k_page_link />
     </cms:if>
     <div class="choose-folders">
      <span><cms:if k_page_foldertitle><cms:show k_page_foldertitle /><cms:else/>Choose folder</cms:if></span><i></i>
      <div>
       <cms:input type="radio" name="new_page_folderid" opt_values="
        <cms:set folder_number='0' />
        <cms:folders masterpage=k_template_name hierarchical="1">
         <cms:if k_folder_id=k_page_folderid>
          <b><cms:if k_folder_parentid!="-1" >- </cms:if><cms:show k_folder_title /></b> = <cms:show k_folder_id />
         <cms:else/>
          <span><cms:if k_folder_parentid!="-1" >- </cms:if><cms:show k_folder_title /></span> = <cms:show k_folder_id />
         </cms:if>
         <cms:set folder_number="<cms:add folder_number '1' />" />
         <cms:if folder_number!=k_total_folders>|</cms:if>
        </cms:folders>"
        opt_selected = "<cms:show k_page_folderid />"
        onchange="this.form.submit()"
       />
      </div>
     </div>
    </cms:form>

Finally some styling (just sample, not so optimized) that provide OnHover appearing of the list and also hides radio-inputs:
Code: Select all
<style>
.choose-folders {
  position: relative;
  width: 200px;
  cursor: pointer;
  background: #9bc7de;
  color: #fff;
}
.choose-folders > span {
  display: block;
  width: 160px;
  line-height: 40px;
  background: #9bc7de;
  padding-left: 14px;
  -webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box
}
.choose-folders > i {
  display: block;
  position: absolute;
  top: 14px;
  right: 14px;
  width: 12px;
  height: 12px;
  background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAMCAYAAABBV8wu /* unwrap this to make one line */
  AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAADVJREFUeNpi/A8EDAwMjAxogBEqwYA /* unwrap this to make one line */
  uiSyBIokuAZfEJgEWxyXBQLIEI9GWMxLtQYwgAQgwAPI2L+dhc0rRAAAAAElFTkSuQmCC') no-repeat 4px 0;
}
.choose-folders > div {
  position: absolute;
  width: 100%;
  display: none;
  background: #fff;
}
.choose-folders > div > label {
  display: block;
  cursor: pointer;
  padding: 7px 14px;
  color: #9e9e9e;
}
.choose-folders > div > label:hover {
  background: #ffffbf;
}
.choose-folders > div input {
  display:none
}
.choose-folders:hover {
  background: #fff;
}
.choose-folders:hover > i {
  background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAG   /* unwrap this to make one line */
  CAYAAAD37n+BAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAADNJREFU   /* unwrap this to make one line */   
  eNpinH383n8GEgATEDOSoJ6RCcYgRjHMBgYiNDEiO4mBgCZGdD/gU4BhAECAAQC+jANVA5fuzgAAAABJRU5ErkJggg==') no-repeat 0 4px;
}
.choose-folders:hover > div {
  display: block;
}
</style>

Unwrap the Base64 strings! This forum doesn't support long strings, so I made two "Enters" to wrap them.

That's it for the Inline Edit! Great result.

UPD: For AdminEdit there is a better solution here: viewtopic.php?f=8&t=7934

Now about AdminEdit. We can't do here onchange="this.form.submit()" because don't want to refresh the page and loose unsaved data. So here is time for a big bunch of RawJS... This script finds selected option and writes it to the root <span> (and gives some extra possibilities for development):
Code: Select all
<script>
function getCheckedValue(radioObj) {
   if(!radioObj)
      return "";
   var radioLength = radioObj.length;
   if(radioLength == undefined)
      if(radioObj.checked)
         return radioObj.value;
      else
         return "";
   for(var i = 0; i < radioLength; i++) {
      if(radioObj[i].checked) {
         return radioObj[i].value;
      }
   }
   return "";
}
function setCheckedValue(radioObj, newValue) {
   if(!radioObj)
      return;
   var radioLength = radioObj.length;
   if(radioLength == undefined) {
      radioObj.checked = (radioObj.value == newValue.toString());
      return;
   }
   for(var i = 0; i < radioLength; i++) {
      radioObj[i].checked = false;
      if(radioObj[i].value == newValue.toString()) {
         radioObj[i].checked = true;
      }
   }
}
function changeTitle(){
   var str = +getCheckedValue(document.forms['frm_edit_page'].elements['new_page_folderid']);
   switch (str) {
      <cms:folders masterpage=k_template_name>
         case <cms:show k_folder_id />: str="<cms:show k_folder_title />"; break;
      </cms:folders>
   }
   document.getElementById('new_folder_title').innerHTML = str;
}
</script>

And also need to slightly modify the DataBound:
Code: Select all
<div class="choose-folders">
   <span id="new_folder_title"><cms:if k_page_foldertitle><cms:show k_page_foldertitle /><cms:else/>Choose folder</cms:if></span><i></i>
   <div>
      <cms:input type="radio" name="new_page_folderid" opt_values="
         <cms:set folder_number='0' />
         <cms:folders masterpage=k_template_name hierarchical="1">
            <span><cms:if k_folder_parentid!="-1" >- </cms:if><cms:show k_folder_title /></span> = <cms:show k_folder_id />
            <cms:set folder_number="<cms:add folder_number '1' />" />
            <cms:if folder_number!=k_total_folders>|</cms:if>
         </cms:folders>"
         onchange="changeTitle()"
      />
   </div>
</div>

Note that there is no Form tag and Success conditionals. The one thing is needed is to add "k_page_folder_id=frm_new_page_folderid" to the root AdminEdit DataBound form, and job is done! Selection of folders doesn't refresh the page, but when press regular "Save" button the changes are applied!

Nice improving of design and usability. And so waiting for Couch 1.4.5 that will create a possibility to fully remake AdminPanel with including own JS libraries and page structure!

Thanks