25 Replies Latest reply on Jun 23, 2010 2:31 PM by [Jongware]

    UI panel and document CS4

    Sara Peroni

      Hi,

       

      I need help.

       

      Is possibile to do an interaction between object group in a indesign CS4 document with a UI dialog opened???

       

      Thank in advance

       

      Sara

        • 1. Re: UI panel and document CS4
          Peter Kahrel Adobe Community Professional & MVP

          With a dialog open, no. With a panel displayed, yes. But maybe you should explain in some more detail what you want.

           

          Peter

          • 2. Re: UI panel and document CS4
            Kasyan Servetsky Level 5

            If you want to create a modeless dialog then define its type as palette:

            var myDialog = new Window('palette', 'Sample Dialog');

             

            Kasyan

            • 3. Re: UI panel and document CS4
              Sara Peroni Level 1

              I want select a item group displayed in page document.

               

              The UI is a new Window('dialog') with a "panel"...

              The target is assign a script label to item.

               

               

              example.jpg

               

               

              • 4. Re: UI panel and document CS4
                Kasyan Servetsky Level 5

                If you want to  interact with page items – e.g. assign a script label –  with your dialog staying open, you should do two things:

                1. define its type as palette
                2. run your script in a custom engine – for example:
                  #targetengine "session"
                • 5. Re: UI panel and document CS4
                  Sara Peroni Level 1

                  Thank guys, it work!

                  • 6. Re: UI panel and document CS4
                    Sara Peroni Level 1

                    I've another problem.

                     

                    I create a window with fixed dimentions.
                    Inside it put a group with a dinamic number of rows.
                    I need to add a "scrollbar" o something that permit to scroll the elements if these are not visible.

                     

                    Is possible?

                    • 7. Re: UI panel and document CS4
                      Kasyan Servetsky Level 5

                      I don't think it's possible -- you can create a scrollable text, but not control elements.

                      • 8. Re: UI panel and document CS4
                        Marc Autret Level 4

                        Actually you can create scrollable widgets or scrollable groups of widgets, but you need to connect and manage the Scrollbar events by yourself. Here is a script (CS4/CS5) that illustrates ScriptUI scrolling:

                         

                        http://www.indiscripts.com/post/2010/06/claquos2-pie-chart-builder-for-indesign

                         

                        Regards,

                        Marc - http://www.indiscripts.com

                        • 9. Re: UI panel and document CS4
                          Kasyan Servetsky Level 5

                          Hi Marc,

                           

                          Since your script is in binary format, could post a sample code illustrating how you do this?

                           

                          Regards,

                          Kasyan

                          • 10. Re: UI panel and document CS4
                            Marc Autret Level 4

                            Hey Kasyan,

                             

                            Since I don't write "native ScriptUI" code anymore, you force me to disclose a part of my secret libraries ;-)

                             

                            That's OK, here is a sample:

                             

                            // testScroller.js
                            // Demonstrates ScriptUI Scrollbar usage
                            //-------------------------------------------------
                            
                            
                            //------------------------------------------------
                            // THE LIBRARIES
                            //------------------------------------------------
                            
                            
                            var DOMEX = DOMEX||(function()
                            // Extended DOM
                            //------------------------------------------------
                            {
                            Window.prototype.focus = (function()
                            //----------------------------
                            // ScriptUI Window focus method
                            {
                            var getActivableControls = function()
                                 { // this: UI object
                                 var r = [], i, c;
                                 for ( i=0 ; i<this.children.length ; ++i )
                                      {
                                      c = this.children[i];
                                      if (c.constructor == StaticText) continue;      // exclude StaticText focus
                                      if (c.constructor == Scrollbar) continue;     // exclude Scrollbar focus
                                      if (c.noTabFocus ) continue;                    // exclude explicit noTabFocus ctrl
                                      if ('active' in c) {r.push(c);continue;}
                                      r = r.concat(arguments.callee.call(c));
                                      }
                                 return r;
                                 };
                            return function(/*int*/step, /*?ctrl*/ac)
                                 { // this: Window
                                 this.controls = this.controls || getActivableControls.call(this);
                                 ac = ac||false;
                                 var sz = this.controls.length, i, c;
                                 for( i=0 ; i<sz ; ++i )
                                      {
                                      c = this.controls[i];
                                      if( ac && c==ac ) break;
                                      if( (!ac) && c.active ) {ac=c; break;}
                                      }
                                 if( !ac ) return;
                                 if( !step ) return ac;
                                 i = (i+step+sz)%sz;
                                 step = (step<0)?-1:1;
                                 while( ac !=(c=this.controls[i]) )
                                      {
                                      if( c.visible && c.enabled ) break;
                                      i = (i+step+sz)%sz;
                                      }
                                 c.active = true;
                                 return c;
                                 };
                            })();
                            
                            Window.prototype.setTabKey = function()
                            //----------------------------
                            // ScriptUI Window set tab key
                                 { // this: Window
                                 this.addEventListener('keydown', function(kev)
                                      {
                                      if( kev.keyName != 'Tab' ) return;
                                      if( kev.ctrlKey || kev.altKey || kev.metaKey ) return;
                                      kev.preventDefault();
                                      this.focus( ((kev.shiftKey)?-1:1 ) );
                                      },false/*==bubble*/);
                                 };
                            
                            /*STATIC*/ Window.UI = function(ui)
                                 { // constructor
                                 var flat = function(container)
                                      { // this: Window.UI
                                      var p,c;
                                      for( p in container )
                                           {
                                           c = container[p];
                                           if( ( !c ) ||
                                                ( typeof c != 'object' ) ||
                                                ( c.propertyIsEnumerable(p) ) ||
                                                ( !('window' in c) ) ||
                                                ( p.substr(0,8) == 'private_' )
                                                ) continue;
                                           this[p] = this[p]||c;
                                           flat.call(this,c);
                                           }
                                      };
                            
                                 var connect = function()
                                      { // this: UI container
                                      var cs = this.children,
                                           i = cs.length,
                                           ci;
                                      while( i-- )
                                           {
                                           ci = cs[i];
                                           if( 'alignChildren' in ci ) connect.call(ci);
                                           if( XW && ('xType' in ci) ) XW.connector(ci.xType).call(ci);
                                           }
                                      };
                            
                                 this.window = new Window(ui.toSource().
                                      slice(1,-1).
                                      replace(RegExp('(?:\\{_([^:]+):)','g'),'$1').
                                      replace(RegExp('}}','g'),'}')
                                      );
                            
                                 this.window.layout.layout();
                                 flat.call(this,this.window);
                                 connect.call(this.window);
                                 this.window.setTabKey();
                                 };
                            
                            return true;
                            })();
                            
                            
                            var XW = XW||(function()
                            // Extended Widgets [v.10-06-14]
                            //------------------------------------------------
                            {
                            var MAC_OS = (File.fs == "Macintosh");
                            var widgets = {};
                            
                            // IconButton
                            // --------
                            widgets.PngButton =
                                 {
                                 ICON_PLUS: String("\u0089PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\b\x06\x00\x00\x00\x1F\u00F3\u00FFa\x00\x00\x00\x04gAMA\x00\x00\u00AF\u00C87\x05\u008A\u00E9\x00\x00\x00\x19tEXtSoftware\x00Adobe ImageReadyq\u00C9e<\x00\x00\x02oIDAT8\u00CB\u00A5\u0093\u00EBK\u0093a\x18\u0087\u00FD[\u00B6/\x05\u0083\u00A4\u0086Y(\u00A8)%X(o\u00D9l\u008A\u008AN\u00DB\u0096sk\u008A\u00CE\u00F6n.\u009D\u00BA\u00CD\x03-\u009D\x13\x0F\x15\u00B5\u00A1\u00DBh\u00A4;8\x0F\u00C3\x03f\u00E2\u00D4\u00D2E\u00EA\u00EBP\u00A2\u008D\"\bj\u00C3\u00AF\u00BF\u00DE\x15MG\u00CB\u0088\x1E\u00F8}y\u00E0\u00BA\u009E\u00E7\u00BE\u00B9\u00EF$\x00I\u00FF\u0093\u00DF.t\u00D3u\u00CC\x0E\u008F\u0084lu\u0089\u00A8\u00E6\tAX\u00FE\u00A2:\u00DC\u00F0\u00BC\u0082\u0092Z\u00CBH\u00D1h1\u00F3D\u0081nZJ\u00B4OJB\u00CF\u00D6{\u00B1\x1AZ\u0084\u00FF\u00F3\x06\u00D6?\u00AD`2`\u0087\u00D2S\x03\u00BE\u0089\x13\u00E2=\u00B9N$\x14\u00FC\u0084\u00C5\u0091\u00E9=;\x0E\u00BE\u00EDa\u00F6\u0083\x0B&j\x10\u008Fw\f\u00B0\u00EF\u009B\u00B0\u00F4q\x0E\u00DA\x05\x19JG\u00F2#\u00DC\u00C1<\"N\u00A0\u009D\u00922h8\u00E8\u00DE\u00B5`\u00EF\u00EB6\u0086\u00B7\u00F5x\u00B8\u00D6\u0081n_+\f~\x1D\u00FA\u00FCZto\u00B6\u00C0}`\x07\u00E9\x11\u00A2\u00D0x%X\u00D0\u009B\u00CD\u0088\thX\u00D1\u00BF\u00AC\u00C6\u00BB/\u009B\u00F4\u008B}\u00E8\u00DD\u00D2B\u00F3J\u0089_G\u00BD&\u0083|Q\b\u00C5r-\u009C\u00FB6\u00DC\x1C\u00C9A\u00DE\u0083\fEL\u00D0\u00E2\u00AC\u00A1\\\x01\x1B\u00FDU3:WUh[\u0091C6+\u008A\t\x046.\x1Af\u00CA \u009D*\u00C6\u00C0\x1B\x1D\u00F4K\u00CD\u00B8\u00DC\u009DF\u00C5\x04\u008Aq\u00FE\u00A1\u00F7\u00BD\x0B\u00FDou4\u00DC\u0084?\x1D\u00F1d\x11\x14\u00F3|X\u00FC\u00C3\u00C8\u00D2\u00A5\x1E\u00C6\x04Mv\u00DE\u00E1D`\f\u00DA\r\x12*_\u00FD\u0089\x02\u00D2[\r\u00AB\x7F\b\u00E9\x1D\u00EC#A\u00BD\u00AD\u009C2\u00FA\u00B40li\u00D0\u00F4R\b\u00F1|\x05x\u00D6\x1Bq`4w=\\\u00F4\u00FB\u00D4\u00E8\u00F2\u00DE\u00C3\x05u\u00F2Q\t\u00E2\u00B1\x12\u00C5m+\x01G\u00C0\x02\u00D9|%$\u00DE\u00D2\x1F5\x1F\x17\u0088\u009C\x1C\u00D4\u00B9\u008B\u00E1\u00D85\u00E3RO*\u00D8\u00F7YGM\x14\u009A\u008B\x18UO\x0B\u0083\u00A4G\u0080qj4\u00D6\u00B0(X\u00EB\u008C&\ns1\u00B1c\u00C2\x1D\u00CB\u00AD(\x1CLV\u009Ef\u00C4\rR\u00F9\u00A3\x02\u00A2d\u00E8j\u00A4\u00D1Q\t'-1\u00FA\u00DAA\u00CETA>U\t\u00E3j\x1B\x1C4,\u00B4p\u00C0V\u00B1\"4L$\x1Ce\u00CE@.A\x18rB\u00F9\x03\u0099\u00E8Y a~m\u0080y\u00C3\x00\u008D\u00B7\x11Y])Q8t\x1CN\u00B8L\u00D7\u00F4\u0099\u00CC\u00DC\u009Et2\u00BB\u00F3\"\u0095\u00A1I\t\u00A7\u00B5\u009F\r\u009Fo=C\u009DS\u00B1\u00C8d\u00E5)\u00E6_\u00B7\u00F1_\u00F3\x1DAF\u00CB\x1F\x00(\u00D3\u00C1\x00\x00\x00\x00IEND\u00AEB`\u0082"),
                                 ICON_MINUS: String("\u0089PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\b\x03\x00\x00\x00(-\x0FS\x00\x00\x00\x19tEXtSoftware\x00Adobe ImageReadyq\u00C9e<\x00\x00\x000PLTE\u00D4\u00A7\u0096\u00E2\u00B5\u00A4\u00E4\u00C5\u00BA\u00CAz[\u00A7cH\u00EF\u00D7\u00CE\u0093Q7\u00F4\u00E8\u00E4\u00CE\u0084h\u00BFdA\u00D3\u0090v\u00D8\u009D\u0086\u00C8uU\u00C5nL\u00FF\u00FF\u00FF\u00FF\u00FF\u00FF\u00A53\x0E}\x00\x00\x00\x10tRNS\u00FF\u00FF\u00FF\u00FF\u00FF\u00FF\u00FF\u00FF\u00FF\u00FF\u00FF\u00FF\u00FF\u00FF\u00FF\x00\u00E0#]\x19\x00\x00\x00\u0087IDATx\u00DA\\\u008F[\x12\u00C4 \b\x04y\u00898\u00E8\u00E6\u00FE\u00B7\r&\u00BB\u00A9\u00CA\u00F6\u0087U\u00B4:\x00\x1D\x7F\u00D0>\u00BA@5\u00B8\u00FFDCJk\u00ACSn\u00D1\u00EAN\u0088Xb\u00C8\x16=\u00B8e\"3Y\u00AD\u0097\x104J\x04P)F%\u00C0\f\u00CC\u008B\u0084\u0095\u0098\u0092\u00F8\\,%\u00DF\u00A2\x1E\u00BCDd\u00C6\\\x17\u0088\u00FD\u0085GMp\x1B\u00F6\x1D\u00DA\u0097\u00F2\u00B7\x1E\u00BE\u00DB\x1Eb\x15\u00A3\x13U\u00CB=\u00BA\u0098\x05e\u00B8\u00CB\u00B3\x1C\u0099\u00BB\u00D3\u00B3\u00DC\u008BS\u0080\x01\x005\u00C3\t\u00EA\u00DEA\u00F0S\x00\x00\x00\x00IEND\u00AEB`\u0082"),
                            
                                 ui: function(ss)
                                      {
                                      var r = {_IconButton:{xType:'PngButton', settings:ss,
                                           noTabFocus:1,
                                           preferredSize:[20,20],
                                           helpTip:ss.helpTip||'',
                                           properties:{style:ss.style||'toolbutton'},
                                           }};
                                      return r;
                                      },
                                 connect: function()
                                      { // <this> IconButton
                                      (function(/*str*/pngStr)
                                           { // Set image
                                           var f = new File(Folder.temp.absoluteURI + '/ib' + (+new Date()) + '.png' );
                                           f.encoding = 'BINARY';
                                           f.open('w');
                                           f.write(pngStr);
                                           f.close();
                                           this.image = ScriptUI.newImage(f.fsName);
                                           f.remove();
                                           }).call(this, widgets[this.xType][this.settings.icon]);
                                      }
                                 };
                            
                            // PanelListBox
                            // --------
                            // Sample:
                            // XW.PanelListBox({clusterType:'{_EditText:{characters:5}}', viewCount:5, defaultItem:{text:'default'}, items:['{text:"aaa"}','{text:"bbb"}']});
                            widgets.PanelListBox =
                                 {
                                 ui: function(ss)
                                      {
                                      ss.viewCount = ss.viewCount||5;
                                      var r = {_Panel:{
                                           xType: 'PanelListBox', settings:ss,
                                           orientation:'row', alignment:'left', alignChildren: 'fill', margins:0, spacing:0,
                                           private_gClusters:{_Group:{orientation:'column', alignChildren:'fill', margins:0, spacing:0}},
                                           private_gScroll:{_Group:{orientation: 'row',alignChildren: 'fill', margins:0, spacing:0,
                                                private_sbStepper:{_Scrollbar:{preferredSize:[20, -1]}}
                                                }},
                                           }};
                                           
                                      var i,
                                           iMax = ss.viewCount-1,
                                           cs = r._Panel.private_gClusters._Group,
                                           buildCluster = function(){
                                                var ret = {_Group:{orientation:'row', alignChildren:'fill', margins:1, spacing:5,
                                                     private_xClusterIn: false,
                                                     private_xTrash: XW.PngButton({icon:'ICON_MINUS',action:'remove', helpTip:ss.trashTip||"Remove the item."}),
                                                     private_xPlus: XW.PngButton({icon:'ICON_PLUS',action:'add', helpTip:ss.addTip||"Add an item."}),
                                                     }};
                                                ret._Group.private_xClusterIn = (new Function('return '+ss.clusterType+';'))();
                                                return ret;
                                                };
                            
                                      for( i=0 ; i <= iMax ; i++ )
                                           cs['private_g'+i] = {_Group:{orientation:'column', alignChildren:'fill', margins:0, spacing:0,
                                                private_xClusterOut: buildCluster(),
                                                private_pLine: (i==iMax)?false:{_Panel:{alignment:'fill'}}
                                                }};
                                      return r;
                                      },
                                 connect: function()
                                      { // <this> UI Panel
                                      var plb = this;
                                      var evChangeCount = ScriptUI.events.createEvent('UIEvent');
                                      evChangeCount.initEvent('changeCount',true,false,true);
                                      evChangeCount.value = 0;
                            
                                      var changeCount = function()
                                           {
                                           evChangeCount.value = scroller.itemCount();
                                           plb.dispatchEvent(evChangeCount);
                                           };
                            
                                      (function()
                                           {
                                           this.offset = this.offset||0;
                                           this.items = this.items||[];
                                           this.maxCount = Math.max(this.items.length, this.maxCount||this.viewCount);
                                           }).call(this.settings);
                                           
                                      var scroller = (function(ss, sb)
                                           { // this: Group (private_gClusters)
                                           var dModel,
                                                iSize,
                                                vSize,
                                                oMax,
                                                ofs;
                                           
                                           dModel = (new Function('return '+ss.defaultItem+';'))();
                            
                                           var setItem = function(/*?obj*/v, /*index*/i, /*max*/mx, /*bool*/ ADDING)
                                                { // this: {obj}
                                                var p,s;
                                                var N_VAR = i+1,
                                                     A_VAR = !!ADDING,
                                                     M_VAR = (+mx)||1;
                                                v = v||{};
                                                for( p in dModel )
                                                     {
                                                     if( p in v ) this[p] = v[p];
                                                     if( !(p in this) )
                                                          {
                                                          this[p]=dModel[p];
                                                          if( (typeof i != 'undefined') && (typeof this[p] == 'string' ) )
                                                               {
                                                               s = this[p].
                                                                    replace(/%N%/g,N_VAR).
                                                                    replace(/%A%/g,A_VAR).
                                                                    replace(/%M%/g,M_VAR);
                                                               if( s[0] == '{' )
                                                                    {
                                                                    try     {
                                                                         s = (new Function('return '+s.substr(1)+';'))();
                                                                         }
                                                                    catch(_){}
                                                                    }
                                                               this[p] = s;
                                                               }
                                                          }
                                                     }
                                                };
                                           var cloneItem = function()
                                                { // this: {obj}
                                                var p,
                                                     r = {};
                                                for( p in dModel ) r[p]=this[p];
                                                return r;
                                                };
                            
                                           var data = (function(/*str[]*/strItems, /*int*/maxCount)
                                                {
                                                var items = [],
                                                     i = Math.min(strItems.length, maxCount),
                                                     v;
                                                while( i-- )
                                                     {
                                                     v = (new Function('return '+strItems[i]+';'))();
                                                     setItem.call(v,undefined,i,i+1);
                                                     items.unshift(v);
                                                     }
                                                return {
                                                     length: function(){return items.length;},
                                                     get: function(i){return items[i];},
                                                     set: function(i,v){setItem.call(items[i],v,i,items.length);},
                                                     remove: function(i) {items.splice(i,1); return items.length;},
                                                     add: function(i){var v={};setItem.call(v,undefined,i+1,1+items.length,true);items.splice(i+1,0,v);return items.length;},
                                                     getItems: function(/*bool*/NO_CLONE)
                                                          {
                                                          if( NO_CLONE ) return items;
                                                          var i = items.length,
                                                               r = [];
                                                          while( i-- ) r.unshift(cloneItem.call(items[i]));
                                                          return r;
                                                          }
                                                     };
                                                })(ss.items, ss.maxCount);
                            
                                           iSize = data.length();
                                           vSize = Math.min(ss.viewCount,iSize);
                                           oMax = +((iSize>vSize)&&(iSize-vSize));
                                           ofs = ss.offset;
                            
                                           var rawOffset = function(/*int*/v, /*bool*/SET_DATA, /*bool*/SET_VIEW)
                                                {
                                                var s = (v<ofs)?1:0,
                                                     kLim = (vSize*s)-(1-s),
                                                     k = (1-s)*(vSize-1),
                                                     s = 2*s-1;
                                                     while( k != kLim )
                                                          {
                                                          if( SET_DATA ) data.set(k+ofs, view.get(k));
                                                          if( SET_VIEW ) view.set(k, data.get(k+v));
                                                          k+=s;
                                                          }
                                                     return ofs=v;
                                                };
                            
                                           var view = (function()
                                                {
                                                var clusters = [],
                                                     i = ss.viewCount,
                                                     cOut, reActive;
                                                
                                                while( i-- )
                                                     {
                                                     cOut = this['private_g'+i]['private_xClusterOut'];
                            
                                                     cOut.index = i;
                                                     cOut.addEventListener('keydown', function(ev)
                                                          { // up/down keys
                                                          reActive = false;
                                                          
                                                          var iFoc = 0;
                                                          var locs, loc, t, chi;
                                                          
                                                          var ii = ((ev.keyName == 'Up')&&-(ofs > 0 || this.index > 0 )) ||
                                                               ((ev.keyName == 'Down')&&+( ofs < oMax || this.index < vSize-1 )) ||
                                                               ((ev.keyName == 'Tab')&&((ev.shiftKey)?-( ofs > 0 && this.index == 0 ):+( ofs < oMax && this.index == vSize-1 )));
                            
                                                          if(! ii ) return;
                                                          ii += this.index;
                                                          if( iFoc = (-(ii==-1)+(ii==vSize)) )
                                                               {
                                                               if( ev.target.constructor == EditText ) ev.target.notify(); // force onChange
                                                               
                                                               sb.safeSet(rawOffset(ofs+iFoc, /*set_data*/true, /*set_view*/true));
                                                               reActive = true;
                                                               if( ev.keyName != 'Tab' )
                                                                    return;
                                                               else
                                                                    ii = this.index-iFoc;
                                                               }
                            
                                                          // searching the corresponding widget up/down
                                                          locs = [(t=ev.target).location];
                                                          while( (t=t.parent) != this )
                                                               {
                                                               locs.push(t.location);
                                                               }
                                                          t = clusters[ii].parent;
                                                          while( loc=locs.pop() )
                                                               {
                                                               t = t.children;
                                                               for( ii = t.length-1 ; ii>=0 ; ii-- )
                                                                    {
                                                                    chi = t[ii];
                                                                    if( chi.location.x != loc.x ) continue;
                                                                    if( chi.location.y != loc.y ) continue;
                                                                    t = chi;
                                                                    break;
                                                                    }
                                                               if( !chi ) {t=false; break;}
                                                               }
                                                          if( t ) t.active = true;
                                                          });
                            
                                                     cOut.addEventListener('keyup', function(ev)
                                                          {
                                                          if( reActive && (ev.keyName == 'Up' || ev.keyName == 'Down') )
                                                               {
                                                               ev.target.active = false;
                                                               ev.target.active = true;
                                                               reActive = false;
                                                               }
                                                          });
                                                          
                                                     cOut.visible = i < vSize;
                                                     cOut.private_xTrash.enabled = iSize>0;
                                                     cOut.private_xPlus.enabled = iSize<ss.maxCount;
                                                     clusters.unshift(cOut['private_xClusterIn']);
                                                     }
                                                     
                                                return {
                                                     get: function(i){return clusters[i];},
                                                     set: function(i,v){setItem.call(clusters[i],v,i,data.length());},
                                                     };
                                                }).call(this);
                                           
                                           return {
                                                maxOffset: function(){return oMax;},
                                                viewSize: function(){return vSize;},
                                                itemCount: function(){return iSize;},
                                                offset: function(/*?int*/v, /*?bool*/NO_DATA_SET)
                                                     {
                                                     if( typeof v == 'undefined' || v > oMax) return ofs;
                                                     return rawOffset(v,/*set data*/!NO_DATA_SET,/*set_view*/true);
                                                     },
                                                remove: function(/*int*/cid)
                                                     {
                                                     if( iSize <= 1 ) return;
                                                     rawOffset(ofs,/*set_data*/true,/*set_view*/false);           // backup every data, don't touch ofs
                                                                                                                           // cid is the cluster-id of the DEL button
                                                     var iData = cid + ofs;                                              // iData is the data-id from which DEL is called
                                                     iSize = data.remove(iData);                                    // remove the data and update iSize
                                                     if( iData == iSize ) iData--;                                   // now iData is the data-id to select finally
                            
                                                     // if necessary, dec vSize and hide the last cluster
                                                     if( vSize > iSize )
                                                          {
                                                          --vSize;
                                                          view.get(vSize).parent.visible = false;
                                                          }
                            
                                                     // vSize now reflects the number of visible clusters (updated)
                                                     oMax = +((iSize>vSize)&&(iSize-vSize));                         // oMax is the new max offset
                            
                                                     // we need to un-scroll(-1) only if ofs>oMax
                                                     if( ofs > oMax ) --ofs;
                            
                                                     // now update the view (from ofs) and update the scrollbar
                                                     rawOffset(ofs,/*set_data*/false,/*set_view*/true);
                                                     sb.safeSet(ofs, oMax);
                            
                                                     // update TRASH / ADD button availability
                                                     view.get(0).parent.private_xTrash.enabled = ( iSize > 1 );
                                                     if( iSize == ss.maxCount-1 )
                                                          {
                                                          cid = ss.viewCount;
                                                          while( cid-- ) view.get(cid).parent.private_xPlus.enabled = true;
                                                          }
                                                     
                                                     // then activate the remaining cluster
                                                     cid = iData-ofs;
                                                     if( 'activate' in view.get(cid) ) view.get(cid).activate();
                                                     
                                                     changeCount();
                                                     },
                                                add: function(/*int*/cid)
                                                     {
                                                     if( iSize >= ss.maxCount ) return;
                                                     rawOffset(ofs,/*set_data*/true,/*set_view*/false);           // backup every data, don't touch ofs
                                                                                                                           // cid is the cluster-id of the ADD button
                                                     var iData = cid + ofs;                                              // iData is the data-id from which ADD is called
                                                     iSize = data.add(iData);                                         // add a new default data AFTER iData, update iSize
                                                     ++iData;                                                            // iData is now the added data-id
                            
                                                     // if necessary, avail a new visible cluster and inc vSize
                                                     if( vSize < ss.viewCount )
                                                          {
                                                          view.get(vSize).parent.visible = true;
                                                          ++vSize;
                                                          }
                                                     // vSize now reflects the number of available clusters (updated)
                                                     oMax = +((iSize>vSize)&&(iSize-vSize));                         // oMax is the new max offset
                            
                                                     // we need to scroll(+1) only if cid is the last cluster in scroll mode ( cid== ss.viewCount-1 )
                                                     if( cid == ss.viewCount-1 ) ++ofs;
                            
                                                     // now update the view (from ofs) and update the scrollbar
                                                     rawOffset(ofs,/*set_data*/false,/*set_view*/true);
                                                     sb.safeSet(ofs,oMax);
                                                     
                                                     // update TRASH / ADD button availability
                                                     view.get(0).parent.private_xTrash.enabled = ( iSize > 1 );
                                                     if( iSize == ss.maxCount )
                                                          {
                                                          cid = ss.viewCount;
                                                          while( cid-- ) view.get(cid).parent.private_xPlus.enabled = false;
                                                          }
                            
                                                     // then activate the added data line
                                                     cid = iData-ofs;
                                                     if( 'activate' in view.get(cid) ) view.get(cid).activate();
                                                     
                                                     changeCount();
                                                     },
                                                getItems: function(/*?bool*/NO_CLONE)
                                                     {
                                                     rawOffset(ofs,/*set_data*/true,/*set_view*/false); // backup data
                                                     return data.getItems(!!NO_CLONE);
                                                     },
                                                updateView: function()
                                                     {
                                                     rawOffset(ofs,/*set_data*/false,/*set_view*/true); // backup data
                                                     },
                                                activate: function(cid)
                                                     {
                                                     if( (cid < vSize) && 'activate' in view.get(cid) ) view.get(cid).activate();
                                                     },
                                                };
                                           }).call(this.private_gClusters, this.settings, this.private_gScroll.private_sbStepper);
                            
                                      (function()
                                           { // this: scrollbar
                                           var SAFE_SETTING = false;
                                           this.safeSet = function(v,mx)
                                                {
                                                SAFE_SETTING = true;
                                                if( typeof mx == 'undefined' )
                                                     {
                                                     this.value = v;
                                                     SAFE_SETTING = false;
                                                     return;
                                                     }
                                                if( mx > 0 && !this.enabled ) this.enabled = true;
                                                if( v >= this.maxvalue )
                                                     {
                                                     this.maxvalue = mx;
                                                     this.value = v;
                                                     }
                                                else
                                                     {
                                                     this.value = v;
                                                     this.maxvalue = mx;
                                                     }
                                                if( mx <= 0 && this.enabled ) this.enabled = false;
                                                SAFE_SETTING = false;
                                                };
                                           var elChange = function(ev)
                                                { // this: scrollbar
                                                if( SAFE_SETTING ) return;
                                                var v = ~~this.value;
                                                if( v!=scroller.offset() ) scroller.offset(v);
                                                };
                                           this.minvalue = 0;
                                           this.maxvalue = scroller.maxOffset();
                                           this.value = scroller.offset();
                                           this.stepdelta = 1;
                                           this.jumpdelta = 20;     // !!important!!
                                           this.enabled = this.maxvalue>0;
                                           this.addEventListener('change', elChange);
                                           this.addEventListener('changing', elChange);
                                           scroller.offset(this.value, /*NO_DATA_SET*/true);
                                           }).call(this.private_gScroll.private_sbStepper);
                                      
                                      (function()
                                           { // this: Group (private_gClusters) <- trash/add button
                                           this.addEventListener('click', function(ev)
                                                {
                                                var tg = ev.target;
                                                if( !tg.xType ) return;
                                                if( tg.xType != 'PngButton' ) return;
                                                if( !tg.settings.action ) return;
                                                scroller[tg.settings.action](tg.parent.index);
                                                });
                                           }).call(this.private_gClusters);
                                      
                                      this.getItems = scroller.getItems;
                                      this.updateView = scroller.updateView;
                                      this.activate = scroller.activate;
                                      this.itemCount = scroller.itemCount;
                                      },
                                 };
                            
                            // XW INTERFACE
                            // --------
                            var xwItf = {}, xt;
                            for( xt in widgets ) xwItf[xt] = widgets[xt].ui;
                            xwItf.connector = function(/*str*/t)
                                 {
                                 if(! (t in widgets) ) return false;
                                 return widgets[t].connect;
                                 };
                            xwItf.addWidget = function(/*str*/_xt, /*obj*/_wg)
                                 {
                                 widgets[_xt] = _wg;
                                 xwItf[_xt] = _wg.ui;
                                 };
                            return xwItf;
                            })();
                            
                            
                            //------------------------------------------------
                            // THE SCRIPT
                            //------------------------------------------------
                            
                            
                            var UserInterface = (function()
                                 {
                                 XW.addWidget('TestRack',
                                      {
                                      ui: function(ss)
                                           {
                                           var r = {_Group:{
                                                xType: 'TestRack', settings:ss,
                                                orientation:'row', margins:[10,4,2,4], spacing:1, alignChildren: 'center', helpTip: ss.helpTip||"",
                                                private_sTest:{_StaticText:{text:'', characters:10, helpTip:"Group..."}},
                                                private_eTest:{_EditText:{text:'',characters:20, helpTip:"Enter the Label of this group."}},
                                                private_bTest:{_Button:{text:'',size:[100,20], helpTip:"Click here to add the label."}},
                                                }};
                                           return r;
                                           },
                                      connect: function()
                                           { // <this> UI Group
                                                
                                           // 'static text' linking
                                           (function(root,sTest)
                                                {
                                                root.sTestValue = '';
                                                root.watch('sTestValue',function(p,ov,nv)
                                                     {
                                                     sTest.text = nv;
                                                     return nv;
                                                     });
                                                })(this, this.private_sTest);
                                                
                                           // 'edittext' linking
                                           (function(root,eTest)
                                                {
                                                root.eTestValue = '';
                                                eTest.addEventListener('change', function(ev)
                                                     {
                                                     root.eTestValue = this.text;
                                                     });
                                                root.watch('eTestValue',function(p,ov,nv)
                                                     {
                                                     eTest.text = nv;
                                                     return nv;
                                                     });
                                                })(this, this.private_eTest);
                            
                                           // 'button' linking
                                           (function(root,bTest)
                                                {
                                                root.bTestValue = '';
                                                bTest.addEventListener('click',function()
                                                     {
                                                     root.bTestValue = bTest.text;
                                                     root.private_eTest.active = true; // focus on label
                                                     });
                                                root.watch('bTestValue',function(p,ov,nv)
                                                     {
                                                     bTest.text = nv;
                                                     return nv;
                                                     });
                                                })(this, this.private_bTest);
                            
                                           this.activate = function()
                                                {
                                                this.private_eTest.active = true;
                                                };
                                           },
                                      });
                            
                                 var ui = new Window.UI({_dialog:{
                                      text: 'Set Group Label',
                                      properties: {closeOnKey: 'OSCmnd+W'},
                                      orientation: 'column',
                                      plTestScroller: XW.PanelListBox({clusterType:'XW.TestRack({})', viewCount:4, maxCount:20,
                                           trashTip: "Delete this line", addTip: "Insert a new line below",
                                           defaultItem: '{sTestValue:"Group %N%", eTestValue:"Label %N%", bTestValue:"Button %N%"}',
                                           items: ['{}','{}','{}'],
                                           }),
                                      gValid: {_Group:{
                                           margins:10, spacing:10, orientation: 'row',
                                           alignChildren: ['center','top'],
                                           bOK: {_Button: {text:"OK"}},
                                           bCancel: {_Button: {text:"Cancel"}},
                                           }},
                                      }});
                            
                                 var w = ui.window;
                                           
                                 // tweak
                                 // ---------------
                                 w.cancelElement = ui.bCancel;
                                 w.defaultElement = ui.bOK;
                                 
                                 var r = ui.window.show();
                                 if( r==2 ) return 'cancel';
                                 return 'ok';
                                 })();
                            

                             

                            The important scrolling stuff is in the widgets.PanelListBox component.

                             

                            @+

                            Marc

                            • 11. Re: UI panel and document CS4
                              Harbs. Level 6

                              Kasyan,

                               

                              You didn't expect something that could be read by mere mortals. Did you?

                               

                              Harbs

                              • 12. Re: UI panel and document CS4
                                [Jongware] Most Valuable Participant

                                I gave up when I saw how long this listing was ...

                                • 13. Re: UI panel and document CS4
                                  Marc Autret Level 4

                                  Well, I admit that my listing is unnecessarily long to illustrate the principle. It contains a lot of extra stuff because it's based on a widget library which manages various other things. And I have not had the courage to rebuild a sample code from scratch...

                                   

                                  However, the principle of scrolling is not that complex. Let's try to explain:

                                   

                                  1) You create a group that only contains placeholders that I'll call clusters. You have a predefined number of clusters in the group, e.g. 4, which correspond to the maximum visible lines in the scroll area at the same time. A cluster can wrap any configuration of ScriptUI components, how ever complicated it is. The scrolling system will only interact with the cluster interface, it doesn't have to know what events occur within a cluster --it's you job to handle inner events for your specific goal (button actions, edittext behaviors, etc.).

                                   

                                  2) Basically, you attach a Scrollbar to the cluster group and you group all in a Panel or a Group which is the root of the scrolling system. The Scrollbar events (change, changing) allow you to manage an offset between zero (minvalue) and a maxvalue which must accordingly reflects the difference between the total number of items in the system and the number of available clusters.

                                   

                                  3) An important idea is that items and clusters are separate entities. Suppose you have 10 items to handle, and 4 available clusters. Each time a Scrollbar event occurs you must record the data changes and load items[i], items[i+1], items[i+2], and items[i+3] in the clusters, where i represents the Scrollbar offset.

                                   

                                  4) As you have understood the scrolling system doesn't actually "scroll" anything. It emulates the effect by updating the contents of immobile widgets. The whole challenge is to link user events and data events from the root system to the inner components, and from the inner components to the root, without presuming any particular configuration within the clusters —since we want to keep the class abstract and reusable for any project). Here is the trickiest part of the code. It is based on three technical points:

                                   

                                  a) Event propagation and management: how work listeners in capturing, bubbling, and at-target phases, how to create custom events, etc.

                                   

                                  b) The watch method: a very powerful tool which allows you to intercept property setting in any object, including ScriptUI widgets, so you can link data management to event triggering.

                                   

                                  c) Code injection through String objects: you can use “evaluable” string at any point of your code by using something like:

                                  var result = (new Function('return '+myStringCode+';'))();

                                  This technique allows to move or delay some processes into the server object while the code can only be defined at the level of the client object. I use it to create on the fly the inner contents of the clusters, or to set the default items. The scrolling system *does not* know anything about what it is actually building inside the clusters, but it knows when it must build something and how to do it, thanks to code strings provided by the client object.

                                   

                                  That's it.

                                   

                                  @+

                                  Marc

                                  • 14. Re: UI panel and document CS4
                                    Bob Stucky Adobe Employee

                                    On Scrollable panels...

                                     

                                    Here's a scrolling panel that I did back in the CS2 days. I have no clue if it would still work or not.

                                     

                                    Not  sure if it'll help, but here it is anyway, and it's not quite as long  as Marc's example....

                                     

                                    Good luck.

                                     

                                         ScrollingImagePanel = function( container, title, width, height,  margin, spacing  ) {
                                             this.container = container;
                                             this.title = title;
                                             this.width = width;
                                             this.height = height;
                                             this.spacing = spacing || 5;
                                             this.margin = margin || 5;
                                             this.group = container.add( "group" );
                                             this.panel = this.group.add( "panel", [ 0, 0, width, height ],  title, { borderStyle: "sunken" } );
                                             this.scrollbar = this.panel.add( "scrollbar", [ ( width - 22 ),  0, ( width - 2 ), height - 10 ] );
                                             this.objects = new Array();
                                             this.scrollbar.objects = this.objects;
                                        
                                             this.objSize = this.width - ( this.margin * 2 ) - 20;  // total  width - margins - width of scroll bar
                                             if ( this.objSize > this.height ) {
                                                 this.objSize = this.height - ( this.margin * 2 ) -  this.spacing;
                                             }
                                             this.scrollbar.panelHeight = this.panel.bounds.bottom -  this.panel.bounds.top;
                                             this.scrollbar.maxvalue = this.objects.length * this.objSize -  this.objSize + 20;
                                             this.scrollbar.stepdelta = this.objSize + this.spacing;
                                             this.scrollbar.jumpdelta = this.scrollbar.panelHeight -  this.objSize + this.spacing;

                                     

                                            this.scrollbar.scroll = function( scrollTo ) {
                                                 for ( var i = 0; i < this.objects.length; i++ ) {
                                                     this.objects[ i ].scroll( scrollTo );
                                                 }
                                             }
                                             this.scrollbar.onChange = function() {
                                                 this.scroll( this.value );
                                             }
                                             this.scrollbar.onChanging = function() {
                                                 this.scroll( this.value );
                                             }
                                         }
                                         ScrollingImagePanel.prototype.add = function( image, imageHilited,  text ) {
                                             var btnTop = this.spacing + ( this.objects.length * (  (  this.objSize - 8 ) ) );
                                             var bounds = [ this.margin, btnTop, this.objSize,( btnTop +  this.objSize - 10 ) ];
                                             var obj = new ScrollingObject( this, bounds, image,  imageHilited, text );
                                             obj.btn.containingWindow = this.container;
                                             this.objects.push( obj );
                                             this.scrollbar.maxvalue = this.objects.length * this.objSize -  this.objSize + 20;
                                             this.scrollbar.minvalue = 0;
                                             return obj;
                                         }
                                         ScrollingObject = function( panel, bounds, image, imageHilited, text  ) {
                                             this.panel = panel;
                                             this.image = image;
                                             this.originalTop = bounds[1];
                                             this.originalBottom = bounds[3];
                                             this.imageHilited = imageHilited;
                                             this.group = panel.panel.add( "panel", bounds, undefined, {  panelStyle: "gray" } );
                                             var iconSize = 50;
                                             var wAvail = bounds[2] - bounds[0];
                                             var hAvail = bounds[3] - bounds[1];
                                             var imgMargin = Math.round( ( wAvail - iconSize ) / 2 );
                                             var imageBounds = [ imgMargin, this.panel.margin, ( bounds[2] -  bounds[0] - ( imgMargin ) ), ( this.panel.margin + iconSize ) ];
                                             this.group.alignChildren = "center";
                                             this.btn = this.group.add( "iconbutton", imageBounds,  this.image, { style: "button" } );
                                             this.btn.onClick = function() {
                                             }
                                             var textBounds = [ 2, imageBounds[3] + 5, bounds[2] - 12,  imageBounds[3] + 45 ];
                                             var stat = this.group.add( "statictext", textBounds, text, {  multiline: true } );
                                             stat.justify = "center";
                                         }
                                         ScrollingObject.prototype.scroll = function( scrollTo ) {
                                             this.group.bounds.top = this.originalTop - scrollTo;
                                             this.group.bounds.bottom = this.originalBottom - scrollTo;
                                         }
                                         ScrollingObject.prototype.toString = function() {
                                             return "[object ScrollingObject]";
                                         }

                                    • 15. Re: UI panel and document CS4
                                      Kasyan Servetsky Level 5

                                      This is tremendous, guys! My special thanks to Marc and Bob.

                                      Kasyan,
                                      You didn't expect something that could be read by mere mortals. Did you?

                                       

                                      I couldn't even imagine that it's possible to do such complex things with Script UI. And surely it's not the stuff I can understand from reading it once -- I'll have to spent some time and make some effort to sort it out.

                                      Eh, how little I know so far!

                                       

                                      Thank you again.

                                       

                                      Kasyan

                                      • 16. Re: UI panel and document CS4
                                        Kasyan Servetsky Level 5

                                        Hi Marc,

                                         

                                        I stumbled upon a problem while exploring your script: when I run it, it stops on this line

                                        var evChangeCount = ScriptUI.events.createEvent('UIEvent');

                                        throwing error -- undefined is not an object

                                         

                                        I tied to comment out the lines relating to the evChangeCount variable and the dialog appeared without an error, but obviously the script doesn't work as expected after that.

                                        I am trying to run it on CS3 (Win). May be your script requires CS4? If not, could you give me a clue how to solve this? Your programming skills are far beyond my level, so I doubt that I can sort it out on my own.

                                         

                                        Thank you in advance.

                                         

                                        Kasyan

                                        • 17. Re: UI panel and document CS4
                                          Marc Autret Level 4

                                          Hi Kasyan,

                                           

                                          My script has been written for ID CS4/CS5 and it probably requires CS4 at least :-(

                                           

                                          Apparently ScriptUI.events is not defined... The fact is that the UIEvent class provides a direct constructor in CS3, while CS4 requires you tu use the ScriptUI.events.createEvent() method first:

                                           

                                          // CS3 syntax

                                          //----------------------

                                          var myEvent = new UIEvent (eventName, canBubble, cancelable, view, detail);

                                           

                                           

                                          // CS4 syntax

                                          //----------------------

                                           

                                          var myEvent =  ScriptUI.events.createEvent('UIEvent');

                                          // then...

                                          myEvent.initEvent(eventName, canBubble,  cancelable, view, detail);

                                           

                                          So maybe you could try to replace the wrong lines by:

                                           

                                          // CS3 (not tested!)

                                          var evChangeCount = new UIEvent('changeCount',true,false,true);
                                          evChangeCount.value = 0;

                                           

                                          I'm not sure it works.

                                           

                                          I also remember that CS3 has a critical bug in managing JS closures that I use a lot (see http://forums.adobe.com/message/2311472).

                                           


                                          @+

                                          Marc

                                          • 18. Re: UI panel and document CS4
                                            Kasyan Servetsky Level 5

                                            Hi Marc,

                                             

                                            This solved the problem -- now it works like a charm.

                                            Thank you very much.

                                             

                                            I noticed that some guys on this forum -- e.g. you and Bob -- use object oriented approach. A few years ago I found and studied Bob's library -- BobsScriptLibrary.jsx -- (thanks to Bob a lot for sharing it, it is very useful).

                                            In this library, he creates an object first

                                            BobsLib = {};

                                            And then adds new objects and methods to it

                                            BobsLib.Log = function( logFile, includeDate ) {

                                            ...

                                             

                                            BobsLib.Log.getDate = function() {

                                            ...

                                             

                                            Adds new methods to predefined File and Folder objects

                                            Folder.prototype.verify = function() {

                                            ...

                                             

                                            Then you can include the library into your script and use these methods.

                                             

                                            But you use a totally different approach which is difficult to comprehend for me. As far as I understand, there are two libraries in your script: DOMEX and XW -- and they are 'wrapped' inside anonymous functions.

                                            var DOMEX = DOMEX||(function()

                                            {

                                            .....

                                            })();

                                             

                                            If variable DOMEX is false, then the function is executed and returns true. Right?

                                            It relates to the point C in your post, doesn't it?

                                            Could you expand more on this or point me where I can read about it?

                                             

                                            I feel that I'm asking silly questions, but I'm a newbie in comparison with you, and want to learn how you do this.

                                             

                                             

                                            Regards,

                                            Kasyan

                                            • 19. Re: UI panel and document CS4
                                              Harbs. Level 6

                                              Hi Kasyan,

                                               

                                              While Marc is very good at what he does, I don't suggest following his style.

                                               

                                              In my opinion, readable code is at least as important as functional code. While anonymous functions have their place, using them as much as Marc does, can make your code very difficult to read and/or debug...

                                               

                                              Also, I'm a big fan of longer variable names where a quick glance tells you what it is...

                                               

                                              Harbs

                                              • 20. Re: UI panel and document CS4
                                                Marc Autret Level 4

                                                Hi Kasyan,

                                                 

                                                Indeed there are different approaches to  create or extend objects. Each has its advantages and counterparts, but  generally there is good reason to choose one over another.

                                                 

                                                An  important point to me is to separate the implementation from the  interface of an object. Think a library as a server, and the code  that uses it as a client. The implementation is about what is  under the hood. The client doesn't need to know how the server makes the  job, it just needs to access to the interface, which is a set of public methods provided by the server.

                                                 

                                                JavaScript doesn't  allow to explicitly define private vs. public class  properties and methods, but we can emulate private members by wrapping  the data and the functions in local variables that the interface can  internally and permanently access to.

                                                 

                                                Now, by declaring  a simple class (as an Object or a Function) at the global level:

                                                 

                                                BobsLib  = {};  // single instance (no constructor needed)

                                                or

                                                BobsLib = function(){}; // allows  instanciation (constructor)


                                                you open many possibilities like  adding static properties or methods (BobsLib.staticMember =  ...), or declaring prototypal members (BobsLib.prototype.member  = ...) to be injected into any future instance through var  myInstance = new BobsLib() -- provided that you declare BobsLib as a Function (constructor).

                                                 

                                                OK. The limitation of this approach is that you  won't be able to isolate and wrap the implementation, in the sense that  everything remains visible on the surface. All BobsLib members  are fully available to the client code, and the object itself could be  changed from outside. If this is your goal, that's OK and the above  syntax is the good one.

                                                 

                                                If you need more  "encapsulation", you can create the library through an anonymous  function which only returns the interface:

                                                 

                                                 

                                                var BobsLib = (function()
                                                {
                                                   // IMPLEMENTATION (PRIVATE)
                                                   var myPrivateProp = /*something*/;
                                                   var myPrivateMethod = function(){/*do something*/};
                                                   /*etc.*/
                                                
                                                   // INTERFACE (PUBLIC)
                                                   return {
                                                      myPublicProp: /*something*/,
                                                      myPublicMethod: function(){/*do something*/},
                                                      /*etc.*/
                                                      };
                                                })(); // the wrapping function is executed now!
                                                

                                                 

                                                Here BobsLib is nothing more than the object returned by the anonymous function. So the client can use BobsLib.myPublicMethod(),  but it has no access to the private stuff. JavaScript is a magical  language in that myPublicMethod can still access to, use and  handle the private stuff. For example, the myPrivateProp variable  is visible from and available to the body of myPublicMethod.  This mechanism is called ‘closure’ --you'll find a lot of web  articles on this subject.

                                                 

                                                That's the general pattern  that I use to create the XW library. It's often an effective  approach to create this kind of tools because a library is basically a singleton (you don't need to create multiple instances through a constructor).

                                                 

                                                The  syntax:

                                                var XW = XW || (...);

                                                is used to prevent  the installer from being re-executed when the object already exists (in a  session engine).

                                                 

                                                DOMEX works differently  in that the installer only returns true, so DOMEX is not an  object, it's a flag that indicates that the installer has been executed.  The job of the DOMEX installer is to extend the DOM. It sets a  few utilities in the global scope and create additive methods to the DOM  objects, like Window.prototype.focus, etc. When DOMEX is  installed (=included), I know that from any point of my code I can use  the helpers functions.

                                                 

                                                There is much to say about variables scope, managing  references, mutable objects, etc., but this could become very boring!...

                                                 


                                                Now,  I agree with Harbs on an essential point. My coding style is only one  approach among many others which are certainly as effective.

                                                 

                                                Is  it "human readable"? It depends on your background in programming. It  is well for my situation because I have a very bad memory and I often  work on large scripts, so I need a lot of modularity and reusability (the basic principle of object encapsulation). I don't think that private  variables (implementation) need to be as long and friendly than the  interface. That's just my opinion. The interface stuff must be  as clear as possible (because it is the bridge to the object, the  visible part offered to the client code), but within an implementation  short variable names suit me better and allow me to write a more compact  code with my own conventions.

                                                 

                                                Another advantage of  (hierarchical) modularity is that I can easily expand or collapse the  parts I'm working on in my code editor (UltraEdit). Conversely I have  great difficulty in reading linear and/or redundant scripts which may  seem more accessible to other programmers. It's really a matter of  habit. Harbs believes that the structure of my code makes it difficult  to debug. This is not the case for me. The internal structure is  systematically arranged in the same way. Implementations are decoupled  as much as possible so when something does not work I quickly found out  where specific action is needed, without worry about impacting the rest  of the application. Finally, I also try to optimize performance and  secure my code, which implies a much narrower use of local variables, and  sometimes condensed syntax that I know to be more effective.

                                                 

                                                @+

                                                Marc

                                                • 21. Re: UI panel and document CS4
                                                  Harbs. Level 6

                                                  Marc,

                                                   

                                                  I didn't mean to imply that your way is "bad" at all. I love looking at your code! It's kind of poetic...

                                                   

                                                  I think the bottom line is that everyone should just stick with what they are used to. Copying someone else does not offer very much gain at all (and a lot to lose in terms of programming time).The only situation where conforming to a single style is useful is on cooperative projects.

                                                   

                                                  I totally agree with what you wrote about programming background. I've found my style has changed a lot as I've learned more programming languages. In terms of (re)using code, I agree that a clear interface is very important. However, when I come back to debug code that I haven't looked at in months (or years), I find that clear variables cuts down a lot on the time it takes me to figure out how it works...

                                                   

                                                  Harbs

                                                  • 22. Re: UI panel and document CS4
                                                    Kasyan Servetsky Level 5

                                                    Hi Marc and Harbs,

                                                     

                                                    Thank you both for your feedback.

                                                    Thank you, Marc, for very detailed and intelligible explanation. It's so interesting to glance behind the master's shoulder and learn new things that seemed to be impossible to do. Your posts are worth reading a dozen books! BTW, I am a regular visitor of your site -- waiting for more tips and tricks.

                                                     

                                                    From your posts, I see that you have strong C programming language background -- you use terms from SDK documentation: implementation, interface, etc. Have you developed plug-ins for InDesign or other Adobe applications?

                                                     

                                                    Thank you again.

                                                     

                                                    Regards,

                                                    Kasyan

                                                    • 23. Re: UI panel and document CS4
                                                      Marc Autret Level 4

                                                      Hi Kasyan,

                                                       

                                                      Thank you for the compliments ;-)

                                                       

                                                      It's  a pleasure to share about our programming know-how. Each brings his  stone to the building, and I reciprocally learn so much here from Dave,  Jongware, Harbs, Peter, you, and many others. Actually one can never  claim to be a "master" in anything about programming. There are so many  methodologies, technologies, sub-languages, API, to assimilate! So let's  say I'm particularly interested in algorithmic aspects and abstraction.  As Jongware, I practice different programming languages as a hobby for  many years — and you're right that I spent more time with C, especially  C++ — but strangely I haven't yet developed a single true plugin for  InDesign. I came to realize over the years that the language is not the  key. . . although I am really unable to return to Basic!

                                                       

                                                      At  the Web beginnings I really hated JavaScript. I was quite a C++  evangelist and an advocate of "pure" OOP. I discovered that I was  completely wrong. Each programming language — even PHP! — brings  something new in how to approach a problem, but all languages today  share a common reason which leads us to another level. That's the point.  The book that really opened my eyes to this subject is the famous Design  Patterns: Elements of Reusable Object-Oriented Software from  the "Gang of Four" (http://en.wikipedia.org/wiki/Design_Patterns). I  highly recommend this reading to anyone who wants to improve its  understanding of basic bricks and its capacity to build a program. Many  concepts used in the InDesign SDK (for example) will be immediately  familiar to you.

                                                       

                                                      Turning specifically to the  JavaScript, I learned most everything that I know from the JS gurus,  especially David Flanagan (http://www.davidflanagan.com/), James  Padolsey (http://james.padolsey.com/), Richard Cornford (http://jibbering.com/faq/notes/closures/), and obviously John Resig (http://ejohn.org/apps/learn/) and Douglas Crockford (http://www.crockford.com/). To conclude, never forget the RTFM rule ;-)  http://www.ecma-international.org/publications/standards/Ecma-262.htm

                                                       

                                                      @+,

                                                      Marc

                                                      • 24. Re: UI panel and document CS4
                                                        Kasyan Servetsky Level 5

                                                        Thanks for the interesting links, Marc. I will check them out without fail.

                                                        I, forone, familiar, more or less, with three scripting languages: JS, AS and VB.From time to time, guys on this forum argue which of them is better, but I believethat knowing all of them provides me with much more ample opportunity. I made apitiful attempt to learn C++ and InDesign SDK -- even procured debug version ofInDesign -- but without any success so far. The main problem is lack of freetime to learn it. I don't even imagine how to approach this task.

                                                         

                                                        Regards,

                                                        Kasyan

                                                        • 25. Re: UI panel and document CS4
                                                          [Jongware] Most Valuable Participant

                                                          I'm fairly proficient in C, less so with C++ -- being entirely self-taught, I marvel at Marc's constructions

                                                           

                                                          The single real plugin I ever wrote was a C version of Peter Kahrel's Compose script for CS (ID 3), because I added so much combo characters to it that the javascript slowed to a crawl, especially when at the end of a document. Fortunately, that particular issue was fixed with CS2, and I'm happily using his script 3 versions of ID later.

                                                           

                                                          At the time, I was impressed by some of the "freebies" it automatically gained as a plugin, such as an automatic history dropdown list (that'd be useful in the javascript version as well ...). After a particularly headache-inducing session trying to make No-Break visible (!), I've never dared touching the SDK again.