Contents
Articles
Behaviors
Books
Director News
Director Web Sites
FAQ
Games
Mailing Lists
News Groups
Project Examples
Reviews
Software
Tools
Useful Web Sites
Utilities
Xtras

Don't miss these
Toggle Button Text
Mastering Macromedia Dreamweaver 3
MediaMacros
Printing Acrobat files with Buddy API
Time Difference
Super Debugging
StopWatch Timer
File Read/Write
Text Shifting
Refine a search - Valentina
 

 

 

Behavior CSS Class

Added on 3/25/2004

 

Compatibilities:
D6_5 D7 D8 D8_5 D9 Mac Parent PC Shockwave

Required Xtras:
PRegEx

This item has not yet been rated

Author: fluxus

Parent script for parsing css-code (as string or as external file) and applying this style to a tagged text (html or custom tags) which will result in a text member formatted accordingly

Download PC Source
--****************************************************************************
-- Software: CSS CLASS
-- Version:  0.2 (pre-alpha)
-- Date:     2004/03/16
-- Author:   Valentin Schmidt (script uses some code from John Dowdell's html-parser
--           and Thomas Björk's php css-parser class)
-- homepage: http://staff.dasdeck.de/valentin/lingo/css_class/
-- Contact:  valentin@dasdeck.de
-- License:  Freeware
--
-- Requirements/Dependencies:
-- - fileIO Xtra for opening external css-files
-- - PRegEx Xtra (or DMX2004) for removing comments (and speeding up other search&replace actions)
--
-- You may use and modify this software as you wish.
--****************************************************************************
property pCss

property pSrcStr
property pTextMem
property pCurrentChunk
property pDefaultStyle -- applied to all text if not overwritten by css
property pStyleStack   -- used for nested tags
property pTagStack     -- used for nested tags
property pIsXHTML      -- tagged text is (x)html

property pRegExFlag    -- RegExp available
property pPRegExFlag   -- PRegEx Xtra available
property pJsRegExFlag  -- RegExp available via JavaScript (DMX2004 or newer)

property pLink


--**************************************
-- PUBLIC
--**************************************

----------------------------------------
--
----------------------------------------
on new me
  pCss=[:]
  pDefaultStyle=["font-family":"Arial","font-size":12,"color":"#000000","text-align":"left","white-space":"pre"] --"line-height":14
  pIsXHTML=FALSE
  
  -- check for utilities-script
  if member("UTILITIES").type<>#script then
    alert("CSSParser needs movie-script 'UTILITIES'!")
    halt()
  end if
  
  -- check for RegExp (PRegEx Xtra or DMX2004)
  pPRegExFlag=xtraPresent("PRegEx")
  if (NOT pPRegExFlag) AND float((the environment).productVersion)>=10 then
    if member("~regexp").memberNum<1 then
      s=new(#script)
      s.name="~regexp"
      s.scripttype=#movie
      s.scriptsyntax=#javascript
      s.scripttext="function _js_RegExReplace(s,pat,rep){return s.replace(RegExp(pat,'g'),rep);}"
    end if
    pJsRegExFlag=1
  end if
  
  pRegExFlag=(pPRegExFlag OR pJsRegExFlag)
  if NOT pRegExFlag then put "Warning: No search&replace with regular expressions available!" -- Script won't remove comments!"
  
  return me
end

----------------------------------------
-- replaces DefaultStyle with given cssStyle
-- cssStyle: proplist, e.g. ["font-family":"Arial","font-size":12,"color":"#000000"]
----------------------------------------
on setDefaultStyle (me, cssStyle)
  pDefaultStyle=cssStyle
end

----------------------------------------
-- adds cssStyle to DefaultStyle (and replaces all identical props)
-- cssStyle: proplist, e.g. ["font-family":"Arial","font-size":12,"color":"#000000"]
----------------------------------------
on addDefaultStyle (me, cssStyle)
  cnt = cssStyle.count
  repeat with i = 1 to cnt
    pDefaultStyle[cssStyle.getPropAt(i)]=cssStyle[i]
  end repeat
end

----------------------------------------
-- parses css file
----------------------------------------
on parseCSSFile (me, cssFile)  
  me.parseCSS(readTxtFile(cssFile))
end

----------------------------------------
-- parses css string
----------------------------------------
on parseCSS (me, cssStr)
  
  -- Remove comments (needs PRegEx Xtra or DMX2004)
  if pRegExFlag then
    cssStr=me._regReplace(cssStr, "/*.+?*/(
|
)*","")
  end if
  
  parts = explode("}",cssStr)
  parts.deleteAt(parts.count)
  
  repeat with part in parts
    l=explode("{",part)
    keyStr  = trim(l[1])
    codeStr = trim(l[2])
    
    keys=explode(",", keyStr)
    repeat with aKey in keys
      if aKey.length>0 then
        if pRegExFlag then
          aKey = me._regReplace(aKey, "(
|
)", "")
        else
          aKey = str_replace(numtochar(10), "", aKey)
          aKey = str_replace(numtochar(13), "", aKey)
        end if
        me._addKey(aKey,codeStr)
      end if
    end repeat
  end repeat
end

----------------------------------------
-- returns css text for given key (or empty string, if key doesn't exist)
----------------------------------------
on getKey (me, aKey)
  aKey = strtolower(aKey)
  
  l=explode(":",aKey)
  tag=l[1]
  if l.count>1 then subtag=l[2]
  else subtag=""
  
  l=explode(".",tag)
  tag=l[1]
  if l.count>1 then class=l[2]
  else class=""
  
  l=explode("#",tag)
  tag=l[1]
  if l.count>1 then id=l[2]
  else id=""
  
  res = [:]
  
  cnt=pCss.count
  repeat with i=1 to cnt
    _tag=pCss.getPropAt(i)
    
    val=pCss[i]
    
    l=explode(":",_tag)
    _tag=l[1]
    if l.count>1 then _subtag=l[2]
    else _subtag=""
    
    l=explode(".",_tag)
    _tag=l[1]
    if l.count>1 then _class=l[2]
    else _class=""
    
    l=explode("#",_tag)
    _tag=l[1]
    if l.count>1 then _id=l[2]
    else _id=""
    
    tagmatch = (tag=_tag) OR (_tag.length=0)
    subtagmatch = (subtag=_subtag) OR (_subtag.length=0)
    classmatch = (class=_class) OR (_class.length=0)
    idmatch = (id=_id)
    
    if (tagmatch AND subtagmatch AND classmatch AND idmatch) then
      if aKey starts "#" then
        temp="#"&id
      else
        temp = _tag
        if ((temp.length > 0) AND (_class.length > 0)) then
          temp = temp & "." & _class
        else if (temp.length=0) then
          temp = "." & _class
        end if
        if ((temp.length > 0) AND (_subtag.length > 0)) then
          temp = temp & ":" & _subtag
        else if (temp.length=0) then
          temp = ":" & _subtag
        end if
      end if
      
      cnt2=pCss[temp].count
      repeat with j=1 to cnt2
        res[pCss[temp].getPropAt(j)] = pCss[temp][j]
      end repeat
      
    end if
  end repeat
  return res
end

----------------------------------------
-- returns css text for given key and prop (or empty string, if key or prop doesn't exist)
----------------------------------------
on getKeyProp (me, aKey, aProp)
  l=me.getKey(aKey)
  return string(l[aProp])
end

----------------------------------------
-- apply css to text member based on tagged text
-- optional flag isXHTML sets some defaults for html-tags, turns off pre-formatted wordwrapping and
-- turns on adding of new lines after "div","/div","p","/p","h1","/h1","h2","/h2","h3","/h3"
----------------------------------------
on applyCSS (me, txtMem, taggedText, isXHTML)
  
  if pRegExFlag then
    -- remove html-comments, xml- and doctype-declarations (needs PRegEx Xtra or DMX2004)
    -- warning: simple and dirty solution: all and removed
    taggedText=me._regReplace(taggedText, "<[!?].+?>(
|
)*", "")
  end if  
  
  pIsXHTML=(isXHTML=TRUE)
  if pIsXHTML then
    -- TEST: remove HTML/HEAD/BODY
    if pRegExFlag then taggedText=me._regReplace(taggedText, "((.*?)|())(
|
)*", "")
    pDefaultStyle["white-space"]="normal" -- html wordwrapping
    
    -- add css for some html tags; you're welcome to add more (like strong, big, small, h1, ...)
    me._addKey("b", "font-weight: bold;")
    me._addKey("i", "font-style: italic;")
    me._addKey("u", "text-decoration: underline;")
    me._addKey("pre",  "white-space: pre; font-family: Courier;")
    me._addKey("a", "text-decoration: underline; color: #0000ff;")
    me._addKey("a:visited", "color: #ff00ff;")
  end if
  
  --put taggedText
  
  pSrcStr = taggedText
  pTextMem = txtMem
  pTagStack = []
  pStyleStack=[]
  pCurrentChunk = ""
  
  pTextMem.text=""
  
  -- apply defaults
  me._applyStyle(pTextMem,pDefaultStyle)
  
  repeat while length(pSrcStr)
    if pSrcStr starts "<" then me._handleTag()
    else me._appendText()
  end repeat
end

--**************************************
-- PRIVATE
--**************************************

----------------------------------------
-- adds key-codeString pair to pCss
----------------------------------------
on _addKey (me, aKey, codeStr)
  aKey = strtolower(aKey)
  codeStr = strtolower(codeStr)
  if (voidP(pCss[aKey])) then
    pCss[aKey] = [:]
  end if
  codes = explode(";",codeStr)
  repeat with code in codes
    code = trim(code)
    l=explode(":",code)
    codekey=l[1]
    if l.count>1 then codevalue=l[2]
    else codevalue=""
    
    if (codekey.length > 0) then
      pCss[aKey][trim(codekey)] = trim(codevalue)
    end if
  end repeat
end

----------------------------------------
-- deletes rest of tag
----------------------------------------
on _deleteRestOfTag me
  the itemDelimiter = ">"
  delete item 1 of pSrcStr
end

----------------------------------------
-- handles text between tags
----------------------------------------
on _appendText me
  the itemDelimiter = "<"
  pCurrentChunk = pSrcStr.item[1]
  
  -- check for wordwrap behaviour:
  -- "white-space"="pre" (or not declared): keep word-wraps
  -- "white-space"="normal": remove word-wraps
  whiteSpace=pDefaultStyle["white-space"]
  repeat with aStyle in pStyleStack
    cnt=aStyle.count
    repeat with i = 1 to cnt
      white=aStyle["white-space"]
      if not voidP(white) then whiteSpace=white
    end repeat
  end repeat
  if whiteSpace="normal" then
    if pRegExFlag then
      pCurrentChunk = me._regReplace (pCurrentChunk, "(
|
)", "")
    else
      pCurrentChunk = str_replace(numtochar(10), "", pCurrentChunk)
      pCurrentChunk = str_replace(numtochar(13), "", pCurrentChunk)
    end if
  end if
  
  delete item 1 of pSrcStr
  put the itemDelimiter before pSrcStr
  
  if pCurrentChunk<>"" AND pTagStack=[] then -- not inside any tag, format with default style
    put pCurrentChunk after pTextMem
  end if
end

----------------------------------------
-- handles start and end tags
----------------------------------------
on _handleTag me
  the itemDelimiter = ">"
  fullTag = ltrim(pSrcStr.item[1])
  delete char 1 of fullTag
  theTag = fullTag.word[1]
  
  if (theTag starts "/") then -- END TAG
        
    if pCurrentChunk<>"" then
      von=pTextMem.text.length+1
      bis=von+pCurrentChunk.length
      put pCurrentChunk after pTextMem
      
      if theTag="/a" AND pIsXHTML then -- add hyperlink
        pTextMem.char[von..bis].hyperlink=pLink
      end if
      
      -- go through stack
      cssStyle=pDefaultStyle.duplicate()
      repeat with aStyle in pStyleStack
        cnt=aStyle.count
        repeat with i = 1 to cnt
          cssStyle[aStyle.getPropAt(i)]=aStyle[i]
        end repeat
      end repeat
      
      me._applyStyle(pTextMem.char[von..bis].ref,cssStyle)
    end if
    
    pTagStack.deleteAt(pTagStack.count)
    pStyleStack.deleteAt(pStyleStack.count)
    
  else if the last char of theTag="/" then -- SINGLE TAG
    if pIsXHTML AND (theTag="br/") then put RETURN after pTextMem
    
  else -- START TAG
    
    -- find class and id
    cnt=fullTag.word.count
    if cnt>1 then
      repeat with i=2 to cnt
        w=fullTag.word[i]
        if (w starts "class=") then
          if pRegExFlag then theClass=me._regReplace(trim(w.char[7..w.char.count]), QUOTE, "")
          else theClass=str_replace(QUOTE,"",trim(w.char[7..w.char.count]))
          theClass=strtolower(theClass)
        else if (w starts "id=") then
          if pRegExFlag then theId=me._regReplace(trim(w.char[4..w.char.count]), QUOTE, "")
          else theId=str_replace(QUOTE,"",trim(w.char[4..w.char.count]))
          theId=strtolower(theId)
        else if (w starts "href=" AND pIsXHTML) then
          put "LINK"
          if pRegExFlag then pLink=me._regReplace(trim(w.char[6..w.char.count]), QUOTE, "")
          else pLink=str_replace(QUOTE,"",trim(w.char[6..w.char.count]))
        end if
        
      end repeat
    end if
    
    -- NESTED TAGS
    if pTagStack<>[] then
      if pCurrentChunk<>"" then
        von=pTextMem.text.length+1
        bis=von+pCurrentChunk.length
        put pCurrentChunk after pTextMem
        
        -- go through stack
        cssStyle=pDefaultStyle.duplicate()
        repeat with aStyle in pStyleStack
          cnt=aStyle.count
          repeat with i = 1 to cnt
            prop=aStyle.getPropAt(i)
            cssStyle[prop]=aStyle[i]
          end repeat
        end repeat
        
        me._applyStyle(pTextMem.char[von..bis].ref,cssStyle)
      end if
    end if
    
    styleTag=theTag
    
    if not voidP(theClass) then
      styleTag=styleTag&"."&theClass
    end if
    
    cssStyle=me.getKey(styleTag)
    
    if not voidP(theId) then
      aStyle=me.getKey("#"&theId)
      cnt=aStyle.count
      repeat with i = 1 to cnt
        cssStyle[aStyle.getPropAt(i)]=aStyle[i]
      end repeat
    end if
    
    -- put tag and corresponding style on stack
    pTagStack.add(styleTag)
    pStyleStack.add(cssStyle)
    
  end if
  
  if pIsXHTML then
    if ["div","/div","p","/p","h1","/h1","h2","/h2","h3","/h3"].getPos(theTag) then
      put RETURN after pTextMem
    end if
  end if
  
  me._deleteRestOfTag()
  pCurrentChunk=""
end

----------------------------------------
-- converts css-style-proplist to director-text-style-props and applies it to text-member-reference
----------------------------------------
on _applyStyle (me, txtRef, cssStyle)
  
  dirStyle=[:]
  fntStyle=[]
  
  cnt=cssStyle.count
  repeat with i = 1 to cnt
    k=cssStyle.getPropAt(i)
    v=cssStyle[i]
    
    case (k) of
      "color":
        dirStyle[#color]=RGB(v)
      "font-family":
        dirStyle[#font]=v
      "font-size":
        dirStyle[#fontsize]=integer(v)
      "line-height":
        dirStyle[#fixedLineSpace]=integer(v)
        
        
      "font-weight": -- bold, normal
        if v="bold" then fntStyle.add(#bold)
        
      "font-style": -- italic , normal
        if v="italic" then fntStyle.add(#italic)
        
      "text-decoration": -- underline, none
        if v="underline" then fntStyle.add(#underline)
        
      "vertical-align": -- super, sub, baseline
        if v="super" then fntStyle.add(#superscript)
        else if v="sub" then fntStyle.add(#subscript)
        
        
      "letter-spacing":
        dirStyle[#charSpacing]=integer(v)
        
      "text-align":
        if v="justify" then v="Full"
        dirStyle[#alignment]=symbol(v)
        
      "margin-left":
        dirStyle[#leftIndent]=integer(v)
      "margin-right":
        dirStyle[#rightIndent]=integer(v)
      "margin-bottom":
        dirStyle[#bottomSpacing]=integer(v)
      "text-indent":
        dirStyle[#firstIndent]=integer(v)
    end case
  end repeat
  
  if fntStyle=[] then fntStyle=[#plain]
  dirStyle[#fontStyle]=fntStyle
  
  cnt=dirStyle.count
  repeat with i = 1 to cnt
    txtRef.setProp(dirStyle.getPropAt(i),dirStyle[i])
  end repeat
  
  -- if no line-height in default and current style, use "natural" line-height (font-size*1.3)
  if voidP(pDefaultStyle.findPos("line-height")) AND voidP(dirStyle.findPos(#fixedLineSpace)) then
    txtRef.setProp(#fixedLineSpace,txtRef.fontsize*1.3)
  end if
  
end

----------------------------------------
-- Search & Replace with RegExp (global)
----------------------------------------
on _regReplace (me, str, pat, rep)
  if pPRegExFlag then
    l=[str]
    PRegEx_Replace(l,pat,"g", rep)
    return  l[1]
  else
    return _js_RegExReplace(str,pat,rep)
  end if
end

 


Contact

MMI
36 South Court Sq
Suite 300
Newnan, GA 30263
USA

Send e-mail