Index: quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/browser/configure.zcml
===================================================================
--- quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/browser/configure.zcml	(revision 1313)
+++ quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/browser/configure.zcml	(revision 1460)
@@ -45,3 +45,11 @@
         />
 
+    <browser:page
+        name="seo-context-properties"
+        for="*"
+        class=".views.SEOContextPropertiesView"
+        layer=".interfaces.IPloneSEOLayer"
+        permission="zope2.View"
+        />
+
 </configure>
Index: quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/browser/keywords.py
===================================================================
--- quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/browser/keywords.py	(revision 1313)
+++ quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/browser/keywords.py	(revision 1460)
@@ -17,4 +17,5 @@
         """ see interface """
         # extract keywords from text
+        import pdb;pdb.set_trace()
         if not text.strip():
             return _(u'Keywords list is empty!')
Index: quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/browser/templates/seo_context_properties.pt
===================================================================
--- quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/browser/templates/seo_context_properties.pt	(revision 1460)
+++ quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/browser/templates/seo_context_properties.pt	(revision 1460)
@@ -0,0 +1,409 @@
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US"
+      xmlns:metal="http://xml.zope.org/namespaces/metal"
+      xmlns:tal="http://xml.zope.org/namespaces/tal"
+      lang="en-US"
+      metal:use-macro="here/main_template/macros/master"
+      i18n:domain="quintagroup.seoptimizer">
+  <metal:border fill-slot="top_slot">
+    <tal:border define="dummy python:request.set('enable_border',1)" />
+  </metal:border>
+  <metal:style_head fill-slot="style_slot">
+      <style type="text/css">
+          tr.datagridwidget-empty-row {
+              display:none;
+          }
+      </style>
+  </metal:style_head>
+  <metal:javascript_head fill-slot="javascript_head_slot">
+      <script type="text/javascript"
+              tal:condition="python:exists('portal/statistics.js')"
+              tal:attributes="src string:${here/absolute_url}/statistics.js">
+      </script>
+      <script type="text/javascript"
+              tal:condition="python:exists('portal/checkkeywords.js')"
+              tal:attributes="src string:${here/absolute_url}/checkkeywords.js">
+      </script>
+      <script type="text/javascript"
+              tal:condition="python:exists('portal/seo_custommetatags.js')"
+              tal:attributes="src string:${here/absolute_url}/seo_custommetatags.js">
+      </script>
+  </metal:javascript_head>
+  <body>
+    <div metal:fill-slot="main"
+        tal:define="errors python:request.get('errors', {})"><!--TODO:implement validation and errors handling-->
+      <h1 i18n:translate="heading_edit_seo_properties">Edit SEO Properties</h1>
+      <div class="documentDescription" i18n:translate="description_edit_seo_properties">
+          This form allows you to edit html header meta tags that are produced by 
+          Plone CMS to incrase Search Engine visibility. The values generated by
+          Plone are present as default values in input fields. To override default
+          value, check corresponding checkbox and input value itself in the 
+          corresponding field.
+        </div>
+      <form name="edit_form" action="." method="post" enctype="multipart/form-data"
+              tal:attributes="action string:${context/absolute_url}/@@seo-context-properties" >
+<!--      <form name="edit_form"
+            action=""
+            method="post"
+            tal:attributes="action string:${here/absolute_url}/${template/getId}">-->
+        <fieldset>
+          <legend i18n:domain="plone" i18n:translate="legend_item_properties">
+            Item Properties
+          </legend>
+  
+          <div class="field">
+            <label i18n:translate="label_page_title_tag" for="seo_title">
+              Page Title Tag
+            </label>
+            <div class="formHelp" i18n:translate="help_seo_title">
+              Text to be present in &lt;TITLE&gt; tag. It is displayed in 
+              browser title bar. Search engines display it as a title of the 
+              document.
+            </div>
+            <input type="checkbox"
+                   id="seo_title_override"
+                   name="seo_title_override"
+                   tabindex=""
+                   tal:attributes="checked python:view.test(here.hasProperty('qSEO_title'), 'on', None);
+                                   tabindex tabindex/next;"
+                   />
+            <label i18n:translate="label_override" for="seo_title_override">
+              Override
+            </label>
+            <br />
+            <input type="text"
+                   id="seo_title"
+                   name="seo_title"
+                   size="40"
+                   value=""
+                   tabindex=""
+                   tal:attributes="value request/seo_title | here/@@seo_context/seo_title;
+                                   tabindex tabindex/next;"
+                   />
+          </div>
+          <div class="field">
+            <label i18n:translate="label_meta_description_tag" for="seo_description">
+              Meta Description Tag
+            </label>
+            <div class="formHelp" i18n:translate="help_seo_description">
+              Description of the document to be indexed by Search Engines. This text will be present in meta description tag in page HTML source. 
+            </div>
+            <input type="checkbox"
+                   id="seo_description_override"
+                   name="seo_description_override"
+                   tabindex=""
+                   tal:attributes="checked python:view.test(here.hasProperty('qSEO_description'), 'on', None);
+                                   tabindex tabindex/next;"
+                   />
+            <label i18n:translate="label_override" for="seo_description_override">
+              Override
+            </label>
+	    <br />
+            <textarea type="text"
+                      id="seo_description"
+                      name="seo_description"
+                      rows="5"
+                      cols="15"
+                      tabindex=""
+                      tal:attributes="tabindex tabindex/next;"
+                      tal:content="request/seo_description | here/@@seo_context/seo_description"
+                      />
+          </div>
+          <div class="field">
+            <label i18n:translate="label_meta_keywords_tag" for="seo_keywords">
+              Meta Keywords Tag
+            </label>
+            <div class="formHelp" i18n:translate="help_seo_keywords">
+              Keywords, the page will be indexed with. 
+              <strong>Enter each keyword in separate line, please.</strong>
+              Though the relevance of listing meta keywords is of 
+              questionable value now, it is useful to set meta keywords for
+              pages - for furture reference.
+            </div>
+            <input type="checkbox"
+                   id="seo_keywords_override"
+                   name="seo_keywords_override"
+                   tabindex=""
+                   tal:attributes="checked python:view.test(here.hasProperty('qSEO_keywords'), 'on', None);
+                                   tabindex tabindex/next;"
+                   />
+            <label i18n:translate="label_override" for="seo_keywords_override">
+              Override
+            </label>
+	    <br />
+            <textarea id="seo_keywords"
+                      name="seo_keywords:lines"
+                      rows="11"
+                      cols="15"
+                      wrap="off"
+                      tabindex=""
+                      tal:attributes="tabindex tabindex/next;"
+                      tal:define="keywords request/seo_keywords | here/@@seo_context/seo_keywords"
+                      tal:content="python:'\n'.join(keywords)"
+                      />
+            <br />
+          </div>
+          <div class="field">
+            <label i18n:translate="label_html_comment" for="seo_html_commment">
+              HTML Comment
+            </label>
+            <div class="formHelp" i18n:translate="help_seo_html_comment">
+              Comments embedded into HTML header.
+            </div>
+            <input type="checkbox"
+                   id="seo_html_comment_override"
+                   name="seo_html_comment_override"
+                   tabindex=""
+                   tal:attributes="checked python:view.test(here.hasProperty('qSEO_html_comment'), 'on', None);
+                                   tabindex tabindex/next;"
+                   />
+            <label i18n:translate="label_override" for="seo_html_comment_override">
+              Override
+            </label>
+            <br />
+            <textarea id="seo_html_comment"
+                      name="seo_html_comment"
+                      rows="5"
+                      cols="15"
+                      tabindex=""
+                      tal:attributes="tabindex tabindex/next;"
+                      tal:content="request/seo_html_comment | here/@@seo_context/seo_html_comment"
+                      />
+          </div>
+          <div class="field">
+            <label i18n:translate="label_robot_tag" for="seo_robots">
+              Robot Tag
+            </label>
+            <div class="formHelp" i18n:translate="help_seo_robots">
+              Robots meta tag value. Allows or denies indexing, following 
+              links, etc. for spiders indexing your content.
+            </div>
+            <input type="checkbox"
+                   id="seo_robots_override"
+                   name="seo_robots_override"
+                   tabindex=""
+                   tal:attributes="checked python:view.test(here.hasProperty('qSEO_robots'), 'on', None);
+                                   tabindex tabindex/next;"
+                   />
+            <label i18n:translate="label_override" for="seo_robots_override">
+              Override
+            </label>
+	    <br />
+            <input type="text"
+                   id="seo_robots"
+                   name="seo_robots"
+                   size="25"
+                   value=""
+                   tabindex=""
+                   tal:attributes="value request/seo_robots | here/@@seo_context/seo_robots;
+                                   tabindex tabindex/next;"
+                   />
+          </div>
+          <div class="field">
+            <label i18n:translate="label_distribution_tag" for="seo_distribution">
+              Distribution Tag
+            </label>
+            <div class="formHelp" i18n:translate="help_seo_distribution">
+              Distribution meta tag to designate time and area disribution
+              of the document.
+            </div>
+            <input type="checkbox"
+                   id="seo_distribution_override"
+                   name="seo_distribution_override"
+                   tabindex=""
+                   tal:attributes="checked python:view.test(here.hasProperty('qSEO_distribution'), 'on', None);
+                                   tabindex tabindex/next;"
+                   />
+            <label i18n:translate="label_override" for="seo_distribution_override">
+              Override
+            </label>
+	    <br />
+            <input type="text"
+                   id="seo_distribution"
+                   name="seo_distribution"
+                   size="25"
+                   value=""
+                   tabindex=""
+                   tal:attributes="value request/seo_distribution | here/@@seo_context/seo_distribution;
+                                   tabindex tabindex/next;"
+                   />
+          </div>
+          <div class="field"
+               tal:define="error errors/seo_canonical|nothing;"
+               tal:attributes="class python:view.test(error, 'field error', 'field')">
+            <label i18n:translate="label_canonical_tag" for="seo_canonical">
+              Canonical URL
+            </label>
+            <div class="formHelp" i18n:translate="help_seo_canonical">
+              Specify your canonical URL.
+              If your site has identical or vastly similar content that's accessible through multiple URLs,
+              this format provides you with more control over the URL returned in search results.
+            </div>
+            <input type="checkbox"
+                   id="seo_canonical_override"
+                   name="seo_canonical_override"
+                   tabindex=""
+                   tal:attributes="checked python:view.test(here.hasProperty('qSEO_canonical'), 'on', None);
+                                   tabindex tabindex/next;"
+                   />
+            <label i18n:translate="label_override" for="seo_canonical_override">
+              Override
+            </label>
+	    <br />
+            <div tal:content="error">Validation error output</div>
+            <input type="text"
+                   id="seo_canonical"
+                   name="seo_canonical"
+                   size="55"
+                   value=""
+                   tabindex=""
+                   tal:attributes="value request/seo_canonical | here/@@seo_context/seo_canonical;
+                                   tabindex tabindex/next;"
+                   />
+          </div>
+          <div class="field"
+               tal:define="fieldName string:seo_custommetatags;
+                           nonEmptylocalMetaTags here/@@seo_context/seo_nonEmptylocalMetaTags;">
+            <label i18n:translate="label_custom_metatags" for="seo_custom_metatags">
+              Custom Meta Tags
+            </label>
+            <div class="formHelp" i18n:translate="help_seo_custommetatags">
+              Here you can manage your custom meta tags. Specify local Meta Tags parameters to be added to the global Meta Tags.  
+              If metacontent field is empty, then a meta tag will not be present on this page.
+            </div>
+            <input type="checkbox"
+                   id="seo_custommetatags_override"
+                   name="seo_custommetatags_override"
+                   tabindex=""
+                   tal:attributes="checked python:view.test(nonEmptylocalMetaTags, 'on', None);
+                                   tabindex tabindex/next;"
+                   />
+            <label i18n:translate="label_override" for="seo_custommetatags_override">
+              Override
+            </label>
+	    <br />
+            <table class="custom-metatags-table"
+                   id="datagridwidget-table-seo_custommetatags"
+                   style="width: 100%"
+                   tal:define="columnNames python:['meta name', 'meta content'];
+                               columnIds   python:['meta_name', 'meta_content'];
+                               globalMT    here/@@seo_context/seo_globalWithoutLocalCustomMetaTags;
+                               localMT    here/@@seo_context/seo_localCustomMetaTags;">
+                <thead>
+                    <tr>
+                        <th class="discreet" style="text-align: left"
+                            tal:repeat="columnName columnNames"
+                            tal:content="columnName"
+                            i18n:translate="">Column name</th>
+                        <th />
+                        <th />
+                    </tr>
+                </thead>
+                <tbody id="datagridwidget-tbody-seo_custommetatags">
+                    <tal:row-loop tal:repeat="row globalMT">
+                        <tr id="datagridwidget-row">
+                            <tal:vars define="fieldId string:${fieldName}_${repeat/row/number}">
+                                <td class="datagridwidget-cell"
+                                    tal:repeat="column columnIds">
+                                    <tal:cell tal:define="cell_value python:row.get(column);">
+                                        <input type="text"
+                                               id="columnId_fieldId"
+                                               value=""
+                                               name="fieldId.columnId:records"
+                                               style="width: 100%;"
+                                               tal:attributes="name string:${fieldName}.${column}:records;
+                                                               id string:${column}_${fieldId};
+                                                               value cell_value"/>
+                                    </tal:cell>
+                                </td>
+                            </tal:vars>
+                        </tr>
+                    </tal:row-loop>
+                    <tal:row-loop tal:repeat="row localMT">
+                        <tr id="datagridwidget-row">
+                            <tal:vars define="fieldId string:${fieldName}_${repeat/row/number}">
+                                <td class="datagridwidget-cell"
+                                    tal:repeat="column columnIds">
+                                    <tal:cell tal:define="cell_value python:row.get(column);">
+                                        <input type="text"
+                                               id="columnId_fieldId"
+                                               value=""
+                                               name="fieldId.columnId:records"
+                                               style="width: 100%;"
+                                               tal:attributes="name string:${fieldName}.${column}:records;
+                                                               id string:${column}_${fieldId};
+                                                               value cell_value"/>
+                                    </tal:cell>
+                                </td>
+                                <td  class="datagridwidget-manipulator">
+                                    <img alt="Delete row"
+                                         onclick="customMetaTagsFunctions.removeFieldRow(this);return false"
+                                         tal:attributes="src string:${portal_url}/delete_icon.gif;" />
+                                </td>
+                                <td class="datagridwidget-hidden-data">
+                                    <input type="hidden"
+                                           tal:attributes="name string:${fieldName}.orderindex_:records;
+                                                           id string:orderindex__${fieldId};
+                                                           value repeat/row/number;" />
+                                </td>
+                            </tal:vars>
+                        </tr>
+                    </tal:row-loop>
+                    <tr id="datagridwidget-empty-row"
+                        class="datagridwidget-empty-row"
+                        tal:define="fieldId string:${fieldName}_new">
+                        <td class="datagridwidget-cell"
+                            tal:repeat="column columnIds">
+                            <span>
+                                <input type="text"
+                                       id="columnId_fieldName_new"
+                                       value=""
+                                       name="fieldName.columnId:records"
+                                       style="width: 100%;"
+                                       tal:attributes="id string:${column}_${fieldName}_new;
+                                                       name string:${fieldName}.${column}:records;" />
+                           </span>
+                        </td>
+                        <td  class="datagridwidget-manipulator">
+                            <img alt="Delete row"
+                                 onclick="customMetaTagsFunctions.removeFieldRow(this);return false"
+                                 tal:attributes="src string:${portal_url}/delete_icon.gif;" />
+                        </td>
+                        <td class="datagridwidget-hidden-data">
+                            <input type="hidden"
+                                   value="template_row_marker"
+                                   tal:attributes="name string:${fieldName}.orderindex_:records;
+                                                  id string:orderindex__${fieldId};" />
+                        </td>
+                    </tr>
+                </tbody>
+            </table>
+            <input type="button"
+                   class="datagridwidget-add-button"
+                   id="datagridwidget-add-button"
+                   value="Add new row"
+                   tal:attributes="onclick string:customMetaTagsFunctions.addRow('${fieldName}')" />
+          </div>
+          <div class="formControls"
+               tal:define="process_creation request/process_creation|nothing;"
+               i18n:domain="plone">
+            <input class="context"
+                   tabindex=""
+                   type="submit"
+                   name="form.button.Save"
+                   value="Save"
+                   i18n:attributes="value"
+                   tal:attributes="tabindex tabindex/next;" />
+            <input class="standalone"
+                   tabindex=""
+                   type="submit"
+                   name="form.button.Cancel"
+                   value="Cancel"
+                   i18n:attributes="value"
+                   tal:attributes="tabindex tabindex/next;" />
+          </div>
+        </fieldset>
+        <input type="hidden" name="form.submitted" value="1" />
+      </form>
+    </div>
+  </body>
+</html>
Index: quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/browser/views.py
===================================================================
--- quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/browser/views.py	(revision 1313)
+++ quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/browser/views.py	(revision 1460)
@@ -9,5 +9,7 @@
 SEPERATOR = '|'
 HAS_CANONICAL_PATH = True
-
+SEO_PREFIX = 'seo_'
+PROP_PREFIX = 'qSEO_'
+SUFFIX = '_override'
 try:
     from quintagroup.canonicalpath.interfaces import ICanonicalPath
@@ -294,2 +296,86 @@
         """
         return self.portal_types.getTypeInfo( type_name )
+
+
+class SEOContextPropertiesView( BrowserView ):
+    """
+    """
+    template = ViewPageTemplateFile('templates/seo_context_properties.pt')
+
+    def updateSEOProps(self, **kw):
+        delete_list, overrides, values = [], [], []
+        seo_items = dict([(k[len(SEO_PREFIX):],v) for k,v in kw.items() if k.startswith(SEO_PREFIX)])
+        for key in seo_items.keys():
+            if key.endswith(SUFFIX):
+                overrides.append(key[:-len(SUFFIX)])
+            else:
+                values.append(key)
+
+
+        for val in values:
+            if val in overrides and seo_items[val+SUFFIX]:
+                setProperty(context, PROP_PREFIX+val, seo_items[val])
+            elif context.hasProperty(PROP_PREFIX+val):
+                delete_list.append(PROP_PREFIX+val)
+        if delete_list: context.manage_delProperties(delete_list)
+        
+    def setProperty(self, property, value, type='string'):
+        context = self.context
+        if context.hasProperty(property):
+            context.manage_changeProperties({property: value})
+        else:
+            context.manage_addProperty(property, value, type)
+
+
+    def __call__( self ):
+        """
+        """
+        context = aq_inner(self.context)
+        request = self.request
+        form = self.request.form
+        submitted = form.get('form.submitted', False)
+        if submitted:
+	    self.updateSEOProps(**form)
+
+
+#delete_list = []
+
+## update custom meta tags
+#property_prefix = 'qSEO_custom_'
+#custom_existing = []
+#for property, value in context.propertyItems():
+    #if property.find(property_prefix) == 0 and len(property) > len(property_prefix):
+        #custom_existing.append(property)
+
+#globalCustomMetaTags = []
+#site_properties = getToolByName(context, 'portal_properties')
+#if hasattr(site_properties, 'seo_properties'):
+    #custom_meta_tags = getattr(site_properties.seo_properties, 'default_custom_metatags', [])
+    #for tag in custom_meta_tags:
+        #name_value = tag.split(SEPERATOR)
+        #if name_value[0]:
+            #globalCustomMetaTags.append({'meta_name'    : name_value[0],
+                                         #'meta_content' : len(name_value) == 1 and '' or name_value[1]})
+
+#custom_updated = []
+#for tag in custommetatags:
+    #meta_name, meta_content = tag['meta_name'], tag['meta_content']
+    #if meta_name:
+        #if not [gmt for gmt in globalCustomMetaTags if (gmt['meta_name']==meta_name and gmt['meta_content']==meta_content)]:
+            #setProperty(context, '%s%s' % (property_prefix, meta_name), meta_content)
+        #custom_updated.append('%s%s' % (property_prefix, meta_name))
+
+##add not updated custom metatags to delete list
+#for tag in custom_existing:
+    #if tag not in custom_updated:
+        #delete_list.append(tag)
+
+#msg ='Content SEO properties have been saved.'
+#try:
+    #context.plone_utils.addPortalMessage(msg)
+    #return state
+#except AttributeError:
+    #return state.set(context=context, portal_status_message=msg)
+            return request.response.redirect(self.context.absolute_url())
+        else:
+            return self.template()
