12 Replies Latest reply on Nov 17, 2009 6:43 AM by Ryan Rutan

    Feature Request: Document Template Kick-Off during Doc Create

    Ryan Rutan

      Basically, this feature is pretty simple to implement, or something like it...as we will be releasing this concept on our community site this March, but it's the concept of Document Templates.   In order to make this work, we had to mildly customize the DocCreateAction, the doc-create.ftl, and add some Extended Properties here and there.  The feature set we were looking to provide were the following:

       

      • Spring board content contributors into a Template that focuses them on content, and less layout.  (more fill in the blank)
      • Global switch to turn on/off the Document Templates feature
      • Global definition of Templates available to all containers
      • Global definition of Default Template selection, this will default the content editor's content.
      • Container definition of Custom Templates, available only for that container
      • Container definition of Default Template (same as above)
      • Auto-Tagging of Documents when template select, helps propogate a standard dimension to slice the community

       

      Basically, our implementation manifests itself as a dropdown about the subject bar, with some JS attached to it to update the TinyMCE editor when a template is changed.  On page-load, the template default and default content are already loaded from the server side, as well as the default tagging structure per the default selection.  On change of the dropdown, a confirmation box asks the user if they want to apped the template and/or replace all of the content.  As such, we check the tags field as well, and attempt to clear out the previous default tag (if that is the only one defined), and replace/add the new corresponding tag.  The System and Container Extended Properties we use share the same naming structure, I hve provided an example below:

       

      Global

      • template.enabled (true/false)
      • template.default = Tutorial
      • template.names = Example,Tutorial
      • template.Example.label = Example Code
      • template.Example.template = <p>...</p>

       

      Container would defined the following:

      • template.default = Textbook  (overrides global if found)
      • template.names = Textbook  (additive to global when in container)
      • template.Textbook.template = <p>...</p>

       

      Here is a screen shot of the drop-down discussed above, all Templates defined under "Custom Templates" are container specific, all above are global.


      Picture 4.png

      As a side note, we also manifested this template "type" information into a Document Extended Property, and customized the SearchAction and view-documents.ftl to add in filters for these template types.  From a separate initiative, we also added in the sorting by columns types.

      Here are some of those screen-shots:

       

      Note: The same global + local container filtering applies here...if I were in a different container where textbook was not definied, I wouldn't see it.

      Picture 5.png

      Also, note the Sort by functionality.  We had to disable it when the "All Documents" were being pulled as that was not constructing a query, instead it pulls from the Recent Content Manager which is cached.

      Picture 6.png

       

      Any ways, I hope this gives you guys some ideas about this feature.  As you can see, the UI's aren't great and true Clearspace-y, but the functionality is there.  Perhaps a richer plugin for TinyMCE to expose this as a drop-down inside the editor?  Anyways, this is a feature that is going to give us a lot of power on our community for styling and content creation and thought I would share with the masses.  I am happy to provide details for those that are interested.

        • Re: Feature Request: Document Template Kick-Off during Doc Create
          Ted Hopton

          I think the lack of a template creation feature is a significant flaw in Clearspace, so this looks terrific to me. This is the second customization I've seen you post, so you guys must have some wizard programmers :-)

           

          I would be grateful if you'd share the code to do this.

            • Re: Feature Request: Document Template Kick-Off during Doc Create
              Ryan Rutan

              It's pretty trivial, but definitely dont have any problems sharing the code.  Our goal was to extract as much value from the feature, without burdening ourself with unnecessary platform customizations.  We were already customizing the DocCreateAction for other purposes, but besides that, the rest of the customizations can be done in FTL and/or a Utility Class...

               

              In com.jivesoftware.community.action.DocCreateAction, we made the following additions:

              /*** STORES THE VALUE OF THE TEMPLATE SELECT, SO WE CAN SET METADATA ON DOCUMENT ***/
              private String m_contentType;
              public String getContentType() { return m_contentType; }
               public void setContentType(String contentType) { m_contentType = contentType; }
              
              public String input() {
                   /***OMITTED OOTB CODE ***/
                      if (isEdit()) {
                        /*** OMITTED OOTB CODE ***/
                      } else {
                      /*** DEFAULT THE CONTENT IN THE EDITOR TO THE DEFAULT FOR THAT CONTAINER ***/
                      StringBuffer sbuf = new StringBuffer("ni.docTemplates.");
                      String templateName = null;
                     
                      /*** DETERMINE IF THE CONTAINER HAS A DEFAULT OVERRIDE, OTHERWISE USE GLOBAL DEFAULT ***/
                      if (getContainer().getProperties().containsKey("ni.docTemplates.default")) {
                      templateName = getContainer().getProperties().get("ni.docTemplates.default");
                      } else {
                      templateName = JiveGlobals.getJiveProperty("ni.docTemplates.default");
                      } // end if
                      sbuf.append(templateName);
                      sbuf.append(".template");
                     
                      /*** USE THE GENERATED PROPERTY NAME TO LOOK FOR THE APPROPRIATE TEMPLATE DEFINITION, CONTAINER 1st ***/
                      String defaultTemplate = null;
                      if (getContainer().getProperties().containsKey(sbuf.toString())) {
                      defaultTemplate = getContainer().getProperties().get(sbuf.toString());
                      } // end if
                     
                      /*** GLOBAL 2nd IF THERE ISNT ONE DEFINED AT THE CONTAINER LEVEL ***/
                      if (defaultTemplate == null) {
                      defaultTemplate = JiveGlobals.getJiveProperty(sbuf.toString(),null);
                      } // end if
                     
                      /*** IF TEMPLATE IS FOUND, DEFAULT BODY AND TAGS TO THE APPROPRIATE VALUES ***/
                      if (defaultTemplate != null) {
                      setBody(defaultTemplate);
                                      /*** WE CONSIDERED ADDING A MORE ROBUST CONFIGURATION HERE, BUT DECIDED THIS WAS SUFFICIENT ***/
                                      setTags(templateName.toLowerCase());
                      } // end if
                      } // end if
              
                      return INPUT;
              }
              
              

               

              On the FTL Side of the house, we updated doc-create.ftl to add a simple drop-down to the enable the selection of the Template.  As noted in the above snippet, on Create, we are pre-seeding the value of the Value with the Template.  We rely on AJAX and JQuery elements to update the UI at RunTime if they change Templates.

               

                      <#assign niDocTemplatesEnabled = JiveGlobals.getJiveBooleanProperty("ni.docTemplates.enabled",false)>
                      <#assign niDocTemplateDefault = JiveGlobals.getJiveProperty("ni.docTemplates.default","Tutorial")>
                      <#if (container.properties?exists && container.properties['ni.docTemplates.default']?exists)>
                      <#assign niDocTemplateDefault = container.properties['ni.docTemplates.default']>
                      </#if>
                      <#if (niDocTemplatesEnabled)>
                              <script type="text/javascript" src="/javascript/global/clearspacex/jquery.doc-templates.js"></script>
                              <#assign availableDocTemplates = JiveGlobals.getJiveProperty("ni.docTemplates.names")>
                              <div id="ni-docTemplates-selection">
                              <input type="hidden" id="contentType" name="contentType" value="<#if (!edit)>${niDocTemplateDefault}</#if>">
                              <input type="hidden" id="containerId" value="${container.ID?c}">
                              <input type="hidden" id="containerType" value="${container.objectType?c}">
                                      <label for="templateSelect"><@s.text name="ni.doc-create.template.lbl"/><@s.text name="global.colon"/></label>
                                      <select size="1" id="templateSelect">
                                              <option value=""><@s.text name="ni.doc-create.template.no-template.lbl"/></option>
                                              <#list availableDocTemplates?split(",") as templateName>
                                                      <#assign templateLabel = JiveGlobals.getJiveProperty("ni.docTemplates.${templateName}.label","${templateName}")>
                                                      <option value="${templateName}" contentType="${templateName}"
                                                      <#if (edit)>
                                                      <#if (document.properties['ni.contentType'] == templateName)>
                                                      selected="selected"
                                                      </#if>
                                                      <#else>
                                                      <#if (niDocTemplateDefault == templateName)>
                                                      selected="selected"
                                                      </#if>                                       
                                                      </#if>
                                                      >${templateLabel}</option>
                                              </#list>
               <#if (container.properties?exists && container.properties['ni.docTemplates.names']?exists)>>
               <#assign availableDocTemplates = container.properties['ni.docTemplates.names']>
               <optgroup label="<@s.text name='ni.custom.container.templates.gtitle' />">
                                               <#list availableDocTemplates?split(",") as templateName>
                                                       <#assign templateLabel = container.properties['ni.docTemplates.${templateName}.label'] ! "${templateName}">
                                                       <option value="${templateName}" contentType="${templateName}"
                                                       <#if (edit)>
                                                       <#if (document.properties['ni.contentType'] == templateName)>
                                                       selected="selected"
                                                       </#if>
                                                       <#else>
                                                       <#if (niDocTemplateDefault == templateName)>
                                                       selected="selected"
                                                       </#if>                                       
                                                       </#if>
                                                       >${templateLabel}</option>
                                               </#list>
                                               </optgroup>
               </#if>
                                      </select>
                              </div>
                      </#if>
              

               

              Our AJAX Action that sends the new templates onChange, calls a very simple action that does a similar switch/check (I've omitted the basics): the only trick on this was making the namespace for this action to allow it to be called from /internal, such that sitemesh didn't stylize the template with the Clearspace header/footer, but everything else was pretty straight forward.

              public String getTemplate() { return m_template; }
               protected void setTemplate(String template) {
               m_template = template;
               } // end get/setTemplate
              
               public String execute() {
               String templateProp = DOCTEMPLATE_PFX+getContentType()+DOCTEMPLATE_SFX;
               setTemplate(JiveGlobals.getJiveProperty(templateProp,null));
               if (getTemplate() == null && m_containerId > 0 && m_containerType > 0) {
               /*** ATTEMPT A CONTAINER LOOKUP ***/
               try {
               JiveContainer container = jiveObjectLoader.getJiveContainer(m_containerType,m_containerId);
               setTemplate(container.getProperties().get(templateProp));
               } catch (NotFoundException nfe) {
               if (Log.isWarnEnabled()) { Log.warn("Invalid Container Values ["+m_containerId+","+m_containerType+"]"); }
               } // end try/catch
               } // end if
               return (getTemplate() != null) ? SUCCESS : ERROR;
               } // end execute
              

              Note:  This is one of the places where we'll want to add FreeMarker processing of the Template value.  Hence the suggestion for a Shared library we can invoke here, and in the DocCreateAction.

               

              Hope this gets you set off on the right foot.  Like I said, it's not 100% perfect...but it's a large step for us in the right direction.  I'm anxiously awaiting a feature similar to this but with more flair from Jive soon. =)

            • Re: Feature Request: Document Template Kick-Off during Doc Create
              casadyc

              Document templates!!  Excellent!!

              • Re: Feature Request: Document Template Kick-Off during Doc Create
                Ryan Rutan

                Dont know how I missed the most obvious of features, that we'll probably want to enable, is the freemarker processing of the Template value...so we can get some dynamic data elements in there.  We'll most definitely add that in our next rendition.

                • Re: Feature Request: Document Template Kick-Off during Doc Create
                  judy.yamada

                  When will document templates be integrated into a Clearspace release as standard functionality?

                  • Re: Feature Request: Document Template Kick-Off during Doc Create
                    Ted Hopton

                    Just had another thought: are you deploying this in Jive SBS 3.0? Any issues using it there as opposed to in 2.5.x?

                      • Re: Feature Request: Document Template Kick-Off during Doc Create
                        Ryan Rutan

                        Not able to upgrade to SBS, so unable to test it out unfortunately.   I'm hoping that this will get on our roadmap sometime before Q3 so we can pick up the latest and greatest later in the year. I'm sure there are changes to the DocCreateAction that I'll have to merge, but it is pretty fundamental and straight forward.  I've seen rumblings about Custom Content-Types in SBS; however, haven't seen anything yet...if it is possible...it would be prudent to re-write this to work as a +1 for the content-types....but in away, I can also see that templates are not always 1 to 1 with a given content-type.

                         

                        Thus far, our users are liking this simple feature that kick-starts them in the right direction...but I can see this working a whole lot better with a feature like custom content-types.

                         

                        RR

                      • Re: Feature Request: Document Template Kick-Off during Doc Create
                        Great stuff, Ryan! And a great conversation, too. This feature enhancement is filed as CS-4626, and it is great to see such an awesome design working for you!
                          • Re: Feature Request: Document Template Kick-Off during Doc Create
                            Ryan Rutan

                            As of SBS we are looking to change direction on the use of Template that we've done thus far.  One limitation to this design is that we couldn't allow Users to control their own templates without involving the community team.  We have streamlined the process under SBS 4.0 and posted an RC1 plugin to share with everyone under SBS 4.0.  Hope everyone likes it...and always welcoming feedback.

                             

                            QuickTemplates Plugin (Moved)

                             

                            We are looking to add more features to this plugin over time...for now this was the big one that we felt, even in its RC1 state...adds a great value to any community.  Hope everyone enjoys.