To participate you must create an account on apostrophenow.org. If you have already done so, click Login.

Changeset 2152

Show
Ignore:
Timestamp:
09/08/10 15:56:27 (17 months ago)
Author:
tboutell
Message:

* The feed slot is now very, very tolerant. It accepts Twitter @usernames, partial URLs with  http:// missing, and URLs of plain old pages. If you provide the URL of a plain old page it examines that page and pulls out the first RSS feed URL referenced via a 'link' element.
* Automatic open of rich text editor when you add a rich text slot is back (this works for any slot that is correctly set up for it in the slot model class)
* Added the same feature to the RSS feed slot
* Refactored edit button JavaScript? into a.js
* The deprecated 'realSlug' property of slot components has been removed as planned. You should be using realUrl by now so your slots can be embedded in non-CMS pages

Location:
plugins/apostrophePlugin/trunk
Files:
7 modified

Legend:

Unmodified
Added
Removed
  • plugins/apostrophePlugin/trunk/lib/action/BaseaSlotComponents.class.php

    r1643 r2152  
    1717    // TODO: remove this workaround in 1.5. All uses of actual_slug and real-slug need to go away 
    1818    // in favor of actual_url, we just don't want to break any old overrides in client projects. 
    19     $this->realSlug = aTools::getRealPage() ? aTools::getRealPage()->getSlug() : 'global'; 
     19     
     20    // Gone in 1.5 
     21     
     22    // $this->realSlug = aTools::getRealPage() ? aTools::getRealPage()->getSlug() : 'global'; 
    2023     
    2124    $this->slot = $this->page->getSlot( 
  • plugins/apostrophePlugin/trunk/lib/form/BaseaFeedForm.class.php

    r1628 r2152  
    1414  { 
    1515    $this->setWidgets(array('url' => new sfWidgetFormInputText(array('label' => 'RSS Feed URL')))); 
    16     $this->setValidators(array('url' => new sfValidatorUrl(array('required' => true, 'max_length' => 1024)))); 
     16   
     17    // "And" is correct, these are really progressive filters improving the URL 
     18     
     19    $this->setValidators(array('url' => new sfValidatorAnd(array( 
     20      // @foo => correct twitter RSS feed URL for that person (requires querying Twitter API) 
     21      new sfValidatorCallback(array('callback' => array($this, 'validateTwitterHandle'))),  
     22      // www.foo.bar => http://www.foo.bar 
     23      new sfValidatorCallback(array('callback' => array($this, 'validateLazyUrl'))),  
     24      // Must be a valid URL to go past this stage 
     25      new sfValidatorUrl(array('required' => true, 'max_length' => 1024)),  
     26      // If the URL is a plain old page get the first RSS feed 'link'ed in it 
     27      new sfValidatorCallback(array('callback' => array($this, 'validateFeed'))))))); 
    1728     
    1829    // Ensures unique IDs throughout the page 
     
    2233     
    2334  } 
     35   
     36  // Convert Twitter handles to RSS feed URLs. Leave anything else alone 
     37  public function validateTwitterHandle($validator, $value) 
     38  { 
     39    if (preg_match('/^@(\w+)$/', $value, $matches)) 
     40    { 
     41      $handle = $matches[1]; 
     42      $info = json_decode(file_get_contents('http://api.twitter.com/1/users/show.json?' . http_build_query(array('screen_name' => $handle))), true); 
     43      if (isset($info['id'])) 
     44      { 
     45        return 'http://twitter.com/statuses/user_timeline/' . $info['id'] . '.rss'; 
     46      } 
     47    } 
     48    return $value; 
     49  } 
     50   
     51  // If it smells like HTML and contains a suitable link tag, extract the first feed URL, 
     52  // which is probably what they meant. Otherwise leave it alone 
     53  public function validateFeed($validator, $value) 
     54  { 
     55    $content = @file_get_contents($value); 
     56    if ($content) 
     57    { 
     58      $html = new DOMDocument(); 
     59      // Incredibly noisy on typical markup 
     60      @$html->loadHTML($content); 
     61      $xpath = new DOMXPath($html); 
     62      $arts = $xpath->query('//link[@rel="alternate" and @type="application/rss+xml"]'); 
     63      if (isset($arts->length) && $arts->length) 
     64      { 
     65        return $arts->item(0)->getAttribute('href'); 
     66      } 
     67    } 
     68    return $value; 
     69  } 
     70  // Add missing http:// 
     71  public function validateLazyUrl($validator, $value) 
     72  { 
     73    if (preg_match('/^[\w\+-]+\./', $value)) 
     74    { 
     75      return 'http://' . $value; 
     76    } 
     77    return $value; 
     78  } 
    2479} 
  • plugins/apostrophePlugin/trunk/lib/model/doctrine/PluginaFeedSlot.class.php

    r2118 r2152  
    1313abstract class PluginaFeedSlot extends BaseaFeedSlot 
    1414{ 
     15  protected $editDefault = true; 
    1516} 
  • plugins/apostrophePlugin/trunk/modules/a/templates/_area.php

    r2144 r2152  
    8888          <?php // Make the slot aware of its permid for simpler JS later ?> 
    8989          <?php a_js_call('$(?).data(?, ?)', "#a-slot-$pageid-$name-$permid", 'a-permid', $permid) ?> 
     90                 
    9091                <?php // Slot Controls ?> 
    9192    <?php if ($editable): ?> 
  • plugins/apostrophePlugin/trunk/modules/a/templates/_simpleEditButton.php

    r2140 r2152  
    2323 
    2424  <li> 
    25   <?php echo jq_link_to_function(isset($label) ? __($label, null, 'apostrophe') : __("edit", null, 'apostrophe'), "",  
     25  <?php // We want to eliminate jQuery helpers, but writing this link as raw HTML is tricky because ?> 
     26  <?php // of the need to quote the title option right. And link_to doesn't like '#' as a URL. So we use ?> 
     27  <?php // content_tag, Symfony's lower-level helper for outputting any tag and its content programmatically ?> 
     28  <?php echo content_tag('a', isset($label) ? a_($label) : a_("edit"),  
    2629                        array( 
     30                          'href' => '#', 
    2731                                'id' => "a-slot-edit-$pageid-$name-$permid", 
    2832                                'class' => isset($class) ? $class : 'a-btn icon a-edit',  
    29                                 'title' => isset($title) ? $title : __('Edit', null, 'apostrophe'),  
     33                                'title' => isset($title) ? $title : a_('Edit'),  
    3034  )) ?> 
    3135 
    32   <script type="text/javascript" charset="utf-8"> 
    33   <?php // TODO: Rewrite this as a button class scoped to ALL edit buttons so there's only a single instance of this Javascript ?> 
    34         $(document).ready(function() { 
    35           <?php // This is now AJAX code to load the edit view on demand ?> 
    36                 var editBtn = $('#a-slot-edit-<?php echo "$pageid-$name-$permid" ?>'); 
    37                 var editSlot = $('#a-slot-<?php echo "$pageid-$name-$permid" ?>'); 
    38                 editBtn.click(function(event){ 
    39                   if (!editSlot.children('.a-slot-content').children('.a-slot-form').length) 
    40                   { 
    41                   $.get(<?php echo json_encode(url_for($slot->type . 'Slot/ajaxEditView') . '?' . http_build_query(array('id' => $pageid, 'slot' => $name, 'permid' => $permid))) ?>, { }, function(data) {  
    42                       editSlot.children('.a-slot-content').html(data); 
    43                       apostrophe.slotShowEditView(editBtn, editSlot); 
    44                     }); 
    45                   } 
    46                   else 
    47                   { 
    48                     // Reuse edit view 
    49                       apostrophe.slotShowEditView(editBtn, editSlot); 
    50                   } 
    51                   return false; 
    52                 }); 
    53         }); 
    54   </script> 
     36  <?php a_js_call('apostrophe.slotEnableEditButton(?, ?, ?, ?)', $pageid, $name, $permid, url_for($slot->type . 'Slot/ajaxEditView')) ?> 
    5537  </li> 
    5638         
  • plugins/apostrophePlugin/trunk/modules/a/templates/_slot.php

    r2139 r2152  
    2222<?php // considerable overhead of loading many instances of FCK we won't use ?> 
    2323 
    24 <?php if ($editable && $updating): ?> 
     24<?php if ($editable && ($updating || $showEditor)): ?> 
    2525  <form method="POST" action="#" class="a-slot-form a-edit-view clearfix" name="a-slot-form-<?php echo $id ?>" id="a-slot-form-<?php echo $id ?>" style="display: <?php echo $showEditor ? "block" : "none" ?>"> 
    2626 
  • plugins/apostrophePlugin/trunk/web/js/a.js

    r2145 r2152  
    464464        } 
    465465         
    466         // This is just the beginning of bigger refactoring needed in this area 
    467         this.slotShowEditView = function(editBtn, editSlot) 
    468         { 
    469                 editBtn.parents('.a-slot, .a-area').addClass('editing-now'); // Apply a class to the Area and Slot Being Edited 
    470                 editSlot.children('.a-slot-content').children('.a-slot-content-container').hide(); // Hide the Content Container 
    471                 editSlot.children('.a-slot-content').children('.a-slot-form').fadeIn(); // Fade In the Edit Form 
    472                 editSlot.children('.a-control li.variant').hide(); // Hide the Variant Options 
    473                 aUI(editBtn.parents('.a-slot').attr('id')); // Refresh the UI scoped to this Slot 
     466        this.slotShowEditView = function(pageid, name, permid) 
     467        {        
     468                var fullId = pageid + '-' + name + '-' + permid; 
     469                var editSlot = $('#a-slot-' + fullId); 
     470          if (!editSlot.children('.a-slot-content').children('.a-slot-form').length) 
     471          { 
     472                  $.get(editSlot.data('a-edit-url'), { id: pageid, slot: name, permid: permid }, function(data) {  
     473              editSlot.children('.a-slot-content').html(data); 
     474              slotShowEditViewPreloaded(pageid, name, permid); 
     475            }); 
     476          } 
     477          else 
     478          { 
     479            // Reuse edit view 
     480      slotShowEditViewPreloaded(pageid, name, permid); 
     481          } 
    474482        } 
    475483         
     
    506514        } 
    507515         
     516        this.slotEnableEditButton = function(pageid, name, permid, editUrl) 
     517        { 
     518                var fullId = pageid + '-' + name + '-' + permid; 
     519                var editBtn = $('#a-slot-edit-' + fullId); 
     520                var editSlot = $('#a-slot-' + fullId); 
     521                editSlot.data('a-edit-url', editUrl); 
     522                editBtn.click(function(event) { 
     523                        apostrophe.slotShowEditView(pageid, name, permid); 
     524                  return false; 
     525                }); 
     526  } 
     527 
    508528        // Private methods callable only from the above (no this.foo = bar) 
    509529        function slotUpdateMoveButtons(id, name, slot, n, slots, updateAction) 
     
    539559                } 
    540560        } 
     561         
     562        function slotShowEditViewPreloaded(pageid, name, permid) 
     563        { 
     564                var fullId = pageid + '-' + name + '-' + permid; 
     565                var editBtn = $('#a-slot-edit-' + fullId); 
     566                var editSlot = $('#a-slot-' + fullId); 
     567                 
     568                editBtn.parents('.a-slot, .a-area').addClass('editing-now'); // Apply a class to the Area and Slot Being Edited 
     569                editSlot.children('.a-slot-content').children('.a-slot-content-container').hide(); // Hide the Content Container 
     570                editSlot.children('.a-slot-content').children('.a-slot-form').fadeIn(); // Fade In the Edit Form 
     571                editSlot.children('.a-control li.variant').hide(); // Hide the Variant Options 
     572                aUI(editBtn.parents('.a-slot').attr('id')); // Refresh the UI scoped to this Slot 
     573        } 
    541574}  
    542575