[ckan-changes] commit/ckan: 2 new changesets

Bitbucket commits-noreply at bitbucket.org
Fri Oct 14 22:07:01 UTC 2011


2 new changesets in ckan:

http://bitbucket.org/okfn/ckan/changeset/b9913d5a9328/
changeset:   b9913d5a9328
branch:      feature-1368-ux-fixes
user:        zephod
date:        2011-10-14 16:03:15
summary:     [ux][s]: Deletions are confirmed with a dialog box.
affected #:  3 files (-1 bytes)

--- a/ckan/logic/schema.py	Fri Oct 14 14:34:47 2011 +0100
+++ b/ckan/logic/schema.py	Fri Oct 14 15:03:15 2011 +0100
@@ -40,7 +40,7 @@
         'revistion_id': [ignore_missing, unicode],
         'resource_group_id': [ignore],
         'package_id': [ignore],
-        'url': [not_empty, unicode],#, URL(add_http=False)],
+        'url': [ignore_empty, unicode],#, URL(add_http=False)],
         'description': [ignore_missing, unicode],
         'format': [ignore_missing, unicode],
         'hash': [ignore_missing, unicode],


--- a/ckan/public/scripts/application.js	Fri Oct 14 14:34:47 2011 +0100
+++ b/ckan/public/scripts/application.js	Fri Oct 14 15:03:15 2011 +0100
@@ -520,15 +520,20 @@
     var collection = this.collection;
     var deleteResource = function(triggerEvent) {
       if (triggerEvent) triggerEvent.preventDefault();
-      collection.remove(resource);
+      confirmMessage = CKAN.Strings.deleteThisResourceQuestion;
+      resourceName = resource.attributes.name || CKAN.Strings.noNameBrackets;
+      confirmMessage = confirmMessage.replace('%name%', resourceName);
+      if (confirm(confirmMessage)) {
+        collection.remove(resource);
+      }
     };
 
     // == Inner Functions: Update the name as you type == //
     var setName = function(newName) { 
       $link = $tr.find('.js-resource-edit-toggle');
-      newName = newName || CKAN.Strings.noNameBrackets;
+      newName = newName || ('<em>'+CKAN.Strings.noNameBrackets+'</em>');
       // Need to structurally modify the DOM to force a re-render of text
-      $link.html('<span>'+newName+'</span>');
+      $link.html('<ema>'+newName+'</span>');
     };
     var nameBoxChanged = function(e) {
       setName($(e.target).val());


--- a/ckan/templates/js_strings.html	Fri Oct 14 14:34:47 2011 +0100
+++ b/ckan/templates/js_strings.html	Fri Oct 14 15:03:15 2011 +0100
@@ -21,7 +21,8 @@
   CKAN.Strings.addDataset = "${_('Add Dataset')}";
   CKAN.Strings.youHaveUnsavedChanges = "${_('You have unsaved changes. Hit Save Changes at the bottom of the page to submit them.')}";
   CKAN.Strings.loading = "${_('Loading...')}";
-  CKAN.Strings.noNameBrackets = '<em>'+"${_('(no name)')}"+'</em>';
+  CKAN.Strings.noNameBrackets = "${_('(no name)')}";
+  CKAN.Strings.deleteThisResourceQuestion = "${_('Delete the resource \'%name%\'?')}"
 
   /*
    * Used in templates.js.


http://bitbucket.org/okfn/ckan/changeset/bd2128be8172/
changeset:   bd2128be8172
branch:      feature-1368-ux-fixes
user:        zephod
date:        2011-10-15 00:06:51
summary:     [ux][l]: Developed new URL slug editor. Repaired tests.
affected #:  21 files (-1 bytes)

--- a/ckan/config/routing.py	Fri Oct 14 15:03:15 2011 +0100
+++ b/ckan/config/routing.py	Fri Oct 14 23:06:51 2011 +0100
@@ -155,7 +155,7 @@
 
     map.connect('/api/2/util/user/autocomplete', controller='api',
         action='user_autocomplete')
-    map.connect('/api/2/util/dataset/create_slug', controller='api', action='create_slug',
+    map.connect('/api/2/util/dataset/is_slug_valid', controller='api', action='is_slug_valid',
                 conditions=dict(method=['GET']))
     map.connect('/api/2/util/tag/autocomplete', controller='api', action='tag_autocomplete',
                 conditions=dict(method=['GET']))


--- a/ckan/controllers/api.py	Fri Oct 14 15:03:15 2011 +0100
+++ b/ckan/controllers/api.py	Fri Oct 14 23:06:51 2011 +0100
@@ -9,7 +9,6 @@
 import ckan.rating
 from ckan.lib.search import query_for, QueryOptions, SearchIndexError, SearchError, DEFAULT_OPTIONS, convert_legacy_parameters_to_solr
 from ckan.plugins import PluginImplementations, IGroupController
-from ckan.lib.munge import munge_title_to_name
 from ckan.lib.navl.dictization_functions import DataError
 from ckan.logic import get_action, check_access
 from ckan.logic import NotFound, NotAuthorized, ValidationError
@@ -562,16 +561,10 @@
         out = map(convert_to_dict, query.all())
         return out
 
-    def create_slug(self):
+    def is_slug_valid(self):
+        slug = request.params.get('slug') or ''
 
-        title = request.params.get('title') or ''
-        name = munge_title_to_name(title)
-        if package_exists(name):
-            valid = False
-        else:
-            valid = True
-        #response.content_type = 'application/javascript'
-        response_data = dict(name=name.replace('_', '-'), valid=valid)
+        response_data = dict(valid=not bool(package_exists(slug)))
         return self._finish_ok(response_data)
 
     def tag_autocomplete(self):


--- a/ckan/controllers/package_formalchemy.py	Fri Oct 14 15:03:15 2011 +0100
+++ b/ckan/controllers/package_formalchemy.py	Fri Oct 14 23:06:51 2011 +0100
@@ -20,8 +20,6 @@
 
     def new(self):
         c.error = ''
-        api_url = config.get('ckan.api_url', '/').rstrip('/')
-        c.package_create_slug_api_url = api_url+h.url_for(controller='api', action='create_slug')
         is_admin = self.authorizer.is_sysadmin(c.user)
         # Check access control for user to create a package.
         try:


--- a/ckan/lib/munge.py	Fri Oct 14 15:03:15 2011 +0100
+++ b/ckan/lib/munge.py	Fri Oct 14 23:06:51 2011 +0100
@@ -7,33 +7,6 @@
 
 from ckan import model
 
-def munge_title_to_name(name):
-    '''Munge a title into a name.
-    '''
-    # remove foreign accents
-    if isinstance(name, unicode):
-        name = substitute_ascii_equivalents(name)
-    # convert spaces and separators
-    name = re.sub('[ .:/]', '-', name)
-    # take out not-allowed characters
-    name = re.sub('[^a-zA-Z0-9-_]', '', name).lower()
-    # remove doubles
-    name = re.sub('--', '-', name)
-    # remove leading or trailing hyphens
-    name = name.strip('-')
-    # if longer than max_length, keep last word if a year
-    max_length = model.PACKAGE_NAME_MAX_LENGTH - 5
-    # (make length less than max, in case we need a few for '_' chars
-    # to de-clash names.)
-    if len(name) > max_length:
-        year_match = re.match('.*?[_-]((?:\d{2,4}[-/])?\d{2,4})$', name)
-        if year_match:
-            year = year_match.groups()[0]
-            name = '%s-%s' % (name[:(max_length-len(year)-1)], year)
-        else:
-            name = name[:max_length]
-    return name
-
 def munge_name(name):
     '''Munges the name field in case it is not to spec.
     '''


--- a/ckan/logic/validators.py	Fri Oct 14 15:03:15 2011 +0100
+++ b/ckan/logic/validators.py	Fri Oct 14 23:06:51 2011 +0100
@@ -111,7 +111,7 @@
         query = query.filter(model.Package.id <> package_id) 
     result = query.first()
     if result:
-        errors[key].append(_('Dataset name already exists in database'))
+        errors[key].append(_('That URL is already in use.'))
 
 def duplicate_extras_key(key, data, errors, context):
 


--- a/ckan/public/css/style.css	Fri Oct 14 15:03:15 2011 +0100
+++ b/ckan/public/css/style.css	Fri Oct 14 23:06:51 2011 +0100
@@ -885,18 +885,23 @@
   display: none;
 }
 
-body.package.new dt.name-label {
-  font-size: 10px;
-}
-
 body.package.new .instructions {
   font-size: 10px;
 }
 
-body.package.new input#name {
-  font-size: 8px;
+body.package.new .url-suffix {
+  font-weight: bold;
+}
 
-  background: #eee;
+body.package.new a.url-edit {
+  font-weight: normal;
+  margin-left: 10px;
+}
+body.package.new .url-input {
+  width: 250px;
+}
+body.package.new dd.name-field {
+  padding-top: 0.2em;
 }
 
 body.package.read #sidebar ul.tags, 
@@ -929,12 +934,8 @@
 /* = Controller-specific tweaks = */
 /* ============================== */
 
-body.group.index #minornavigation { 
-  visibility: hidden; 
-}
-
 body.package.search #minornavigation { 
-  visibility: hidden; 
+  display: none;
 }
 body.package.search #menusearch {
   display: none;
@@ -943,7 +944,6 @@
 body.index.home #minornavigation {
   display: none;
 }
-
 body.index.home #sidebar {
   display: none;
 }


Binary file ckan/public/images/icons/pencil.png has changed


--- a/ckan/public/scripts/application.js	Fri Oct 14 15:03:15 2011 +0100
+++ b/ckan/public/scripts/application.js	Fri Oct 14 23:06:51 2011 +0100
@@ -26,7 +26,10 @@
 
     var isDatasetNew = $('body.package.new').length > 0;
     if (isDatasetNew) {
+      // Set up magic URL slug editor
+      CKAN.Utils.setupUrlEditor();
       $('#save').val(CKAN.Strings.addDataset);
+      $("#title").focus();
     }
 
     // Buttons with href-action should navigate when clicked
@@ -71,6 +74,104 @@
 
   };
 
+  my.bindInputChanges = function(input, callback) {
+    input.keyup(callback);
+    input.keydown(callback);
+    input.keypress(callback);
+    input.change(callback);
+  };
+
+  my.setupUrlEditor = function() {
+    // Page elements to hook onto
+    var titleInput = $('.js-title');
+    var urlText = $('.js-url-text');
+    var urlSuffix = $('.js-url-suffix');
+    var urlInput = $('.js-url-input');
+    var validMsg = $('.js-url-is-valid');
+
+    // Title api verifies package name availability
+    var api_url = '/api/2/util/dataset/is_slug_valid';
+    // (make length less than max, in case we need a few for '_' chars to de-clash slugs.)
+    var MAX_SLUG_LENGTH = 90;
+
+    var titleChanged = function() {
+      var lastTitle = "";
+      var regexToHyphen = [ new RegExp('[ .:/_]', 'g'), 
+                        new RegExp('[^a-zA-Z0-9-_]', 'g'), 
+                        new RegExp('-+', 'g')];
+      var regexToDelete = [ new RegExp('^-*', 'g'), 
+                        new RegExp('-*$', 'g')];
+
+      var titleToSlug = function(title) {
+        var slug = title;
+        $.each(regexToHyphen, function(idx,regex) { slug = slug.replace(regex, '-'); });
+        $.each(regexToDelete, function(idx,regex) { slug = slug.replace(regex, ''); });
+        slug = slug.toLowerCase();
+
+        if (slug.length<MAX_SLUG_LENGTH) {
+            slug=slug.substring(0,MAX_SLUG_LENGTH);
+        }
+        return slug;
+      };
+
+      // Called when the title changes
+      return function() {
+        var title = titleInput.val();
+        if (title == lastTitle) return;
+        lastTitle = title;
+
+        slug = titleToSlug(title);
+        urlInput.val(slug);
+        urlInput.change();
+      };
+    }();
+
+    var urlChanged = function() {
+      var timer = null;
+
+      var checkSlugValid = function(slug) {
+        $.ajax({
+          url: api_url,
+          data: 'slug=' + slug,
+          dataType: 'jsonp',
+          type: 'get',
+          jsonpCallback: 'callback',
+          success: function (data) {
+            if (data.valid) {
+              validMsg.html('<span style="font-weight: bold; color: #0c0">'+CKAN.Strings.datasetNameAvailable+'</span>');
+            } else {
+              validMsg.html('<span style="font-weight: bold; color: #c00">'+CKAN.Strings.datasetNameNotAvailable+'</span>');
+            }
+          }
+        });
+      }
+
+      return function() {
+        slug = urlInput.val();
+        urlSuffix.html('<span>'+slug+'</span>');
+        validMsg.html('<span style="color: #777;">'+CKAN.Strings.checking+'</span>');
+        if (timer) clearTimeout(timer);
+        timer = setTimeout(function () {
+          checkSlugValid(slug);
+        }, 200);
+      };
+    }();
+
+    // Hook title changes to the input box
+    my.bindInputChanges(titleInput, titleChanged);
+    my.bindInputChanges(urlInput, urlChanged);
+    // Set up the form
+    urlChanged();
+
+    $('.js-url-editlink').live('click',function(e) {
+      e.preventDefault();
+      $('.js-url-viewmode').hide();
+      $('.js-url-editmode').show();
+      urlInput.select();
+      urlInput.focus();
+    });
+  }
+
   // Attach dataset autocompletion to provided elements
   //
   // Requires: jquery-ui autocomplete
@@ -286,116 +387,6 @@
     });  
   };
 
-  // Name slug generator for $name element using $title element
-  //
-  // Also does nice things like show errors if name not available etc
-  //
-  // Usage: CKAN.Utils.PackageSlugCreator.create($('#my-title'), $('#my-name'))
-  my.PackageSlugCreator = (function() {
-    // initialize function
-    // 
-    // args: $title and $name input elements
-    function SlugCreator($title, $name) {
-      this.name_field = $name;
-      this.title_field = $title;
-      // Keep a variable where we can store whether the name field has been
-      // directly modified by the user or not. If it has, we should no longer
-      // fetch updates.
-      this.name_changed = false;
-      // url for slug api (we need api rather than do it ourself because we check if available)
-      this.url = '/api/2/util/dataset/create_slug';
-      // Add a new element where the validity of the dataset name can be displayed
-      this.name_field.parent().append('<div id="dataset_name_valid_msg"></div>');
-      this.title_field.blur(this.title_change_handler())
-      this.title_field.keyup(this.title_change_handler())
-      this.name_field.keyup(this.name_change_handler());
-      this.name_field.blur(this.name_blur_handler());
-    }
-
-    SlugCreator.create = function($title, $name) {
-      return new SlugCreator($title, $name);
-    }
-
-    SlugCreator.prototype.title_change_handler = function() {
-      var self = this;
-      return function() {
-        if (!self.name_changed && self.title_field.val().replace(/^\s+|\s+$/g, '')) {
-          self.update(self.title_field.val(), function(data) {self.name_field.val(data.name)});
-        }
-      }
-    }
-
-    SlugCreator.prototype.name_blur_handler = function() {
-      var self = this;
-      return function() {
-        // Reset if the name is emptied
-        if (!self.name_field.val().replace(/^\s+|\s+$/g, '')){
-          self.name_changed = false;
-          $('#dataset_name_valid_msg').html('');
-        } else {
-          self.update(self.name_field.val(), function(data) {
-              self.name_field.val(data.name)
-          });
-        }
-      };
-    }
-
-    SlugCreator.prototype.name_change_handler = function() {
-      var self = this;
-      return function() {
-        // Reset if the name is emptied
-        if (!self.name_field.val().replace(/^\s+|\s+$/g, '')){
-          self.name_changed = false;
-          $('#dataset_name_valid_msg').html('');
-        } else {
-          self.name_changed = true;
-          self.update(self.name_field.val(), function(data) {
-            if (self.name_field.val().length >= data.name) {
-                self.name_field.val(data.name);
-            }
-          });
-        }
-      };
-    }
-
-    // Create a function for fetching the value and updating the result
-    SlugCreator.prototype.perform_update = function(value, on_success){
-      var self = this;
-      $.ajax({
-        url: self.url,
-        data: 'title=' + value,
-        dataType: 'jsonp',
-        type: 'get',
-        jsonpCallback: 'callback',
-        success: function (data) {
-          if (on_success) {
-            on_success(data);
-          }
-          var valid_msg = $('#dataset_name_valid_msg');
-          if (data.valid) {
-            valid_msg.html('<span style="font-weight: bold; color: #0c0">'+CKAN.Strings.datasetNameAvailable+'</span>');
-          } else {
-            valid_msg.html('<span style="font-weight: bold; color: #c00">'+CKAN.Strings.datasetNameNotAvailable+'</span>');
-          }
-        }
-      });
-    }
-
-    // We only want to perform the update if there hasn't been a change for say 200ms
-    var timer = null;
-    SlugCreator.prototype.update = function(value, on_success) {
-      var self = this;
-      if (this.timer) {
-        clearTimeout(this.timer)
-      };
-      this.timer = setTimeout(function () {
-        self.perform_update(value, on_success)
-      }, 200);
-    }
-
-    return SlugCreator;
-  })();
-
   return my;
 }(jQuery, CKAN.Utils || {});
 
@@ -545,10 +536,7 @@
     }
 
     var nameBox = $tr.find('input.js-resource-edit-name');
-    nameBox.change(nameBoxChanged);
-    nameBox.keydown(nameBoxChanged);
-    nameBox.keyup(nameBoxChanged);
-    nameBox.keypress(nameBoxChanged);
+    CKAN.Utils.bindInputChanges(nameBox,nameBoxChanged);
 
     $tr.find('.js-resource-edit-toggle').click(toggleOpen);
     $tr.find('.js-resource-edit-delete').click(deleteResource);


--- a/ckan/templates/group/index.html	Fri Oct 14 15:03:15 2011 +0100
+++ b/ckan/templates/group/index.html	Fri Oct 14 23:06:51 2011 +0100
@@ -7,14 +7,9 @@
   <py:def function="page_heading">Groups of Datasets</py:def><div py:match="content">
-
     ${c.page.pager()}
     ${group_list_from_dict(c.page.items)}
     ${c.page.pager()}
-    
-    <py:choose test="">
-
-    </py:choose></div><xi:include href="layout.html" />


--- a/ckan/templates/group/layout.html	Fri Oct 14 15:03:15 2011 +0100
+++ b/ckan/templates/group/layout.html	Fri Oct 14 23:06:51 2011 +0100
@@ -8,34 +8,34 @@
 
   <py:match path="primarysidebar"><li class="widget-container boxed widget_text">
-      <h3>Groups section</h3>
-      <p i18n:msg="">Whilst tags are great at collecting datasets together, there are occasions when you want to restrict users from editing a collection. A <strong>group</strong> can be set-up to specify which users have permission to add or remove datasets from it.</p>
-      <p>
-	<span class="ckan_logged_in" style="display: none;" i18n:msg="">
-	  To create a new group, please first <a href="${h.url_for(controller='user',action='login', id=None)}">login</a>.
-	</span>
-	<span class="ckan_logged_out">
-	  <a href="${h.url_for(controller='group',action='new', id=None)}">Create a new group</a>
-	</span>
-      </p>
+      <h3>What Are Groups?</h3>
+      <span i18n:msg="">Whilst tags are great at collecting datasets together, there are occasions when you want to restrict users from editing a collection. A <strong>group</strong> can be set-up to specify which users have permission to add or remove datasets from it.</span></li></py:match>
 
-  <py:match path="minornavigation" py:if="c.group">
-  <ul class="tabbed">
-    <li py:attrs="{'class':'current-tab'} if c.action=='read' else {}">${h.subnav_link(c, h.icon('group') + _('View'), controller='group', action='read', id=c.group.name)}</li>
-    <li py:attrs="{'class':'current-tab'} if c.action=='edit' else {}" py:if="h.check_access('group_update',{'id':c.group.id})">
-      ${h.subnav_link(c, h.icon('group_edit') + _('Edit'), controller='group', action='edit', id=c.group.name)}
-    </li>
-    <li py:attrs="{'class':'current-tab'} if c.action=='history' else {}">${h.subnav_link(c, h.icon('page_white_stack') + _('History'), controller='group', action='history', id=c.group.name)}</li>
-    <li py:attrs="{'class':'current-tab'} if c.action=='authz' else {}" py:if="h.check_access('group_edit_permissions',{'id':c.group.id})">
-      ${h.subnav_link(c, h.icon('lock') + _('Authorization'), controller='group', action='authz', id=c.group.name)}
-    </li>
-    <!-- li class="action">
-    ${h.subnav_link(c, h.icon('atom_feed') + _('Subscribe'),
-    controller='group', action='history', id=c.group.name, format='atom', days=7)}
-    </li-->
-  </ul>
+  <py:match path="minornavigation">
+    <ul py:if="c.group" class="tabbed">
+      <li py:attrs="{'class':'current-tab'} if c.action=='read' else {}">${h.subnav_link(c, h.icon('group') + _('View'), controller='group', action='read', id=c.group.name)}</li>
+      <li py:attrs="{'class':'current-tab'} if c.action=='edit' else {}" py:if="h.check_access('group_update',{'id':c.group.id})">
+        ${h.subnav_link(c, h.icon('group_edit') + _('Edit'), controller='group', action='edit', id=c.group.name)}
+      </li>
+      <li py:attrs="{'class':'current-tab'} if c.action=='history' else {}">${h.subnav_link(c, h.icon('page_white_stack') + _('History'), controller='group', action='history', id=c.group.name)}</li>
+      <li py:attrs="{'class':'current-tab'} if c.action=='authz' else {}" py:if="h.check_access('group_edit_permissions',{'id':c.group.id})">
+        ${h.subnav_link(c, h.icon('lock') + _('Authorization'), controller='group', action='authz', id=c.group.name)}
+      </li>
+      <!-- li class="action">
+      ${h.subnav_link(c, h.icon('atom_feed') + _('Subscribe'),
+      controller='group', action='history', id=c.group.name, format='atom', days=7)}
+      </li-->
+    </ul>
+    <ul py:if="not c.group" class="tabbed">
+      <li py:attrs="{'class':'current-tab'} if c.action=='index' else {}">
+        ${h.subnav_link(c, h.icon('group') + _('List Groups'), controller='group', action='index')}
+      </li>
+      <li py:attrs="{'class':'current-tab'} if c.action=='new' else {}">
+        ${h.subnav_link(c, h.icon('group_add') + _('Add a Group'), controller='group', action='new')}
+      </li>
+    </ul></py:match><xi:include href="../layout.html" />


--- a/ckan/templates/group/new.html	Fri Oct 14 15:03:15 2011 +0100
+++ b/ckan/templates/group/new.html	Fri Oct 14 23:06:51 2011 +0100
@@ -2,8 +2,8 @@
   xmlns:xi="http://www.w3.org/2001/XInclude"
   py:strip="">
   
-  <py:def function="page_title">New - Groups</py:def>
-  <py:def function="page_heading">New Group</py:def>
+  <py:def function="page_title">Add A Group</py:def>
+  <py:def function="page_heading">Add A Group</py:def><div py:match="content">
     ${Markup(c.form)}


--- a/ckan/templates/group/new_group_form.html	Fri Oct 14 15:03:15 2011 +0100
+++ b/ckan/templates/group/new_group_form.html	Fri Oct 14 23:06:51 2011 +0100
@@ -13,7 +13,6 @@
 </div><fieldset>
-  <legend>Details</legend><dl><dt><label class="field_opt" for="name">Name *</label></dt><dd><input id="name" name="name" type="text" value="${data.get('name', '')}"/></dd>
@@ -38,7 +37,7 @@
 </fieldset><fieldset>
-  <legend>Extras</legend>
+  <h3>Extras</h3><dl><py:with vars="extras = data.get('extras', [])"><py:for each="num, extra in enumerate(data.get('extras', []))">
@@ -63,7 +62,7 @@
 </fieldset><fieldset>
-  <legend>Datasets</legend>
+  <h3>Datasets</h3><dl py:if="data.get('packages')"><py:for each="num, package in enumerate(data.get('packages'))"><dt><input checked="checked" id="datasets__${num}__name" name="packages__${num}__name" type="checkbox" value="${package['name']}"/></dt>
@@ -76,9 +75,7 @@
 </fieldset><fieldset>
-  <legend>
-    Add datasets
-  </legend>
+  <h3>Add datasets</h3><dl><dt><label class="field_opt" for="packages__${len(data.get('packages', []))}__name">Dataset</label></dt><dd><input class="autocomplete-dataset" id="datasets__${len(data.get('packages', []))}__name" name="packages__${len(data.get('packages', []))}__name" type="text" /></dd>


--- a/ckan/templates/js_strings.html	Fri Oct 14 15:03:15 2011 +0100
+++ b/ckan/templates/js_strings.html	Fri Oct 14 23:06:51 2011 +0100
@@ -14,6 +14,7 @@
    * Used in application.js.
    */
   CKAN.Strings.helloWorld = "${_('Hello there, world!')}";
+  CKAN.Strings.checking = "${_('Checking...')}";
   CKAN.Strings.datasetNameAvailable = "${_('This dataset name is available!')}";
   CKAN.Strings.datasetNameNotAvailable = "${_('This dataset name is already used, please use a different name')}";
   CKAN.Strings.bracketsNone = "${_('(none)')}";


--- a/ckan/templates/package/edit.html	Fri Oct 14 15:03:15 2011 +0100
+++ b/ckan/templates/package/edit.html	Fri Oct 14 23:06:51 2011 +0100
@@ -19,9 +19,9 @@
       <ul class="edit-form-navigation"><!-- One button for each fieldset --><li><a href="#section-basic-information">Basic Information</a></li>
+        <li><a href="#section-further-information">Futher Information</a></li><li><a href="#section-resources">Resources</a></li>
-        <li><a href="#section-groups">Groups</a></li>
-        <li><a href="#section-detail">Details</a></li>
+        <li><a href="#section-groups">Groups & Tags</a></li><li><a href="#section-extras">Extras</a></li></ul></li>


--- a/ckan/templates/package/new.html	Fri Oct 14 15:03:15 2011 +0100
+++ b/ckan/templates/package/new.html	Fri Oct 14 23:06:51 2011 +0100
@@ -8,16 +8,6 @@
 
   <py:def function="body_class">hide-sidebar</py:def>
 
-  <py:def function="optional_footer">
-    <!-- Auto-generate 'name' field -->
-    <script type="text/javascript">
-      jQuery(document).ready(function($) {
-        CKAN.Utils.PackageSlugCreator.create($('#title'), $('#name'));
-        $("#title").focus();
-      });
-    </script>
-  </py:def>
-
   <div py:match="content"><h3 py:if="c.error" class="form-errors">
       Error: ${c.error}


--- a/ckan/templates/package/new_package_form.html	Fri Oct 14 15:03:15 2011 +0100
+++ b/ckan/templates/package/new_package_form.html	Fri Oct 14 23:06:51 2011 +0100
@@ -31,32 +31,47 @@
     <dt class="title-label"><label class="field_opt" for="title">Title</label></dt><dd class="title-field"><input id="title"
-        tabindex="1" name="title" type="text"
+        class="js-title"
+        name="title" type="text"
         value="${data.get('title', '')}"
         placeholder="${_('A short descriptive title for the dataset')}"
       /></dd><dd class="title-instructions field_error" py:if="errors.get('title', '')">${errors.get('title', '')}</dd>
 
-    <dt class="name-label"><label class="field_req" for="name">Slug *</label></dt>
-    <dd class="name-field"><input id="name" tabindex="999" maxlength="100" name="name" type="text" value="${data.get('name', '')}" /></dd>
-    <dd class="name-instructions instructions basic">A unique identifier used in urls. Renaming is possible but discouraged.</dd>
-    <dd class="name-instructions hints">2+ characters, lowercase, using only 'a-z0-9' and '-_'</dd>
-    <dd class="name-instructions field_error" py:if="errors.get('name', '')">${errors.get('name', '')}</dd>
+    <dt class="name-label"><label class="field_req" for="name">Url</label></dt>
+    <dd class="name-field">
+      <span class="url-text">http://thedatahub.org/dataset/<span class="js-url-viewmode js-url-suffix"> </span><a href="#" class="url-edit js-url-editlink js-url-viewmode">(edit)</a></span>
+      <input style="display: none;" id="name" maxlength="100" name="name" type="text" class="url-input js-url-editmode js-url-input" value="${data.get('name', '')}" />
+      <p class="js-url-is-valid"> </p>
+    </dd>
+    <dd style="display: none;" class="js-url-editmode name-instructions instructions basic">A unique identifier used in urls. Renaming is possible but discouraged.</dd>
+    <dd style="display: none;" class="js-url-editmode name-instructions hints">2+ characters, lowercase, using only 'a-z0-9' and '-_'</dd>
+    <dd style="display: none;" class="js-url-editmode name-instructions field_error" py:if="errors.get('name', '')">${errors.get('name', '')}</dd><dt class="homepage-label"><label class="field_opt" for="url">Home Page</label></dt>
-    <dd class="homepage-field"><input id="url" tabindex="2" name="url" type="text" value="${data.get('url', '')}"/></dd>
+    <dd class="homepage-field"><input id="url" name="url" type="text" value="${data.get('url', '')}"/></dd><dd class="homepage-instructions instructions basic">The URL for the web page describing the data (not the data itself).</dd><dd class="homepage-instructions hints">e.g. http://www.example.com/growth-figures.html</dd><dd class="homepage-instructions field_error" py:if="errors.get('url', '')">${errors.get('url', '')}</dd>
 
+    <dt class="license-label"><label class="field_opt" for="license_id">License</label></dt>
+    <dd class="license-field">
+      <select id="license_id" name="license_id">
+        <py:for each="licence_desc, licence_id in c.licences">
+          <option value="${licence_id}" py:attrs="{'selected': 'selected' if data.get('license_id', '') == licence_id else None}" >${licence_desc}</option>
+        </py:for>
+      </select>
+    </dd>
+    <dd class="license-instructions instructions basic">The licence under which the dataset is released.</dd>
+
     <dt class="description-label"><label class="field_opt" for="notes">Description</label></dt><dd class="description-field"><div class="markdown-editor"><ul class="button-row"><li><button class="pretty-button js-markdown-edit depressed">Edit</button></li><li><button class="pretty-button js-markdown-preview">Preview</button></li></ul>
-      <textarea class="markdown-input" tabindex="3" name="notes" id="notes" placeholder="${_('Start with a summary sentence ...')}">${data.get('notes','')}</textarea>
+      <textarea class="markdown-input" name="notes" id="notes" placeholder="${_('Start with a summary sentence ...')}">${data.get('notes','')}</textarea><div class="markdown-preview" style="display: none;"></div><span class="hints">You can use <a href="http://daringfireball.net/projects/markdown/syntax" target="_blank">Markdown formatting</a> here.</span><!--
@@ -64,25 +79,6 @@
       <dd class="instructions further">It is often displayed with the dataset title. In particular, it should start with a short sentence that describes the dataset succinctly, because the first few words alone may be used in some views of the datasets.</dd>
       --></div></dd>
-
-    <dt class="license-label"><label class="field_opt" for="license_id">License</label></dt>
-    <dd class="license-field">
-      <select id="license_id" tabindex="4" name="license_id">
-        <py:for each="licence_desc, licence_id in c.licences">
-          <option value="${licence_id}" py:attrs="{'selected': 'selected' if data.get('license_id', '') == licence_id else None}" >${licence_desc}</option>
-        </py:for>
-      </select>
-    </dd>
-    <dd class="license-instructions instructions basic">The licence under which the dataset is released.</dd>
-
-    <dt class="tags-label"><label class="field_opt" for="tags">Tags</label></dt>
-    <dd class="tags-field">
-      <input class="long autocomplete-tag" tabindex="5" id="tag_string" name="tag_string" size="60" type="text" 
-               value="${data.get('tag_string') or ' '.join([tag['name'] for tag in data.get('tags', [])])}" />
-    </dd>
-    <dd class="tags-instructions instructions basic" i18n:msg="">Terms that may link this dataset to similar ones. For more information on conventions, see <a href="http://wiki.okfn.org/ckan/doc/faq#TagConventions">this wiki page</a>.</dd>
-    <dd class="tags-instructions hints">e.g. pollution rivers water-quality</dd>
-    <dd class="tags-instructions field_error" py:if="errors.get('tag_string', '')">${errors.get('tag_string', '')}</dd></dl></fieldset>
 
@@ -111,6 +107,7 @@
 </fieldset><fieldset id="groups">
+  <h3>Groups</h3><dl><py:for each="num, group in enumerate(data.get('groups', []))"><?python
@@ -134,10 +131,21 @@
         </py:for></select></dd> 
-    <dd py:if="not c.groups_available">Cannot add any groups.</dd>
+    <dd py:if="not c.groups_available"><em>Cannot add any groups.</em></dd>
+  </dl>
+  <h3>Tags</h3>
+  <dl>
+    <dt class="tags-label"><label class="field_opt" for="tags">Tags</label></dt>
+    <dd class="tags-field">
+      <input class="long autocomplete-tag" id="tag_string" name="tag_string" size="60" type="text" 
+               value="${data.get('tag_string') or ' '.join([tag['name'] for tag in data.get('tags', [])])}" />
+    </dd>
+    <dd class="tags-instructions instructions basic" i18n:msg="">Terms that may link this dataset to similar ones. For more information on conventions, see <a href="http://wiki.okfn.org/ckan/doc/faq#TagConventions">this wiki page</a>.</dd>
+    <dd class="tags-instructions hints">e.g. pollution rivers water-quality</dd>
+    <dd class="tags-instructions field_error" py:if="errors.get('tag_string', '')">${errors.get('tag_string', '')}</dd></dl></fieldset>
-<fieldset id='detail'>
+<fieldset id='further-information'><dl><dt><label class="field_opt" for="author">Author</label></dt><dd><input id="author" name="author" type="text" value="${data.get('author', '')}" /></dd>
@@ -208,9 +216,9 @@
 </div><div class="form-submit">
-  <input id="save" tabindex="99" class="pretty-button primary" name="save" type="submit" value="${_('Save Changes')}" />
+  <input id="save" class="pretty-button primary" name="save" type="submit" value="${_('Save Changes')}" /><py:if test="c.pkg">
-    <input id="cancel" tabindex="100" class="pretty-button href-action" name="cancel" type="reset" value="${_('Cancel')}" action="${h.url_for(controller='package', action='read', id=c.pkg.name)}" />
+    <input id="cancel" class="pretty-button href-action" name="cancel" type="reset" value="${_('Cancel')}" action="${h.url_for(controller='package', action='read', id=c.pkg.name)}" /></py:if><p i18n:msg="" class="hints"><strong>Important:</strong> By submitting content, you agree to release your contributions under the <a href="http://opendatacommons.org/licenses/odbl/1.0/">Open Database License</a>. Please <strong>refrain</strong> from editing this page if you are <strong>not</strong> happy to do this.


--- a/ckan/tests/functional/api/test_ajax.py	Fri Oct 14 15:03:15 2011 +0100
+++ b/ckan/tests/functional/api/test_ajax.py	Fri Oct 14 23:06:51 2011 +0100
@@ -14,15 +14,26 @@
     def teardown(cls):
         model.repo.rebuild_db()
         
-    def test_package_create_slug(self):
+    def test_package_slug_valid(self):
+        CreateTestData.create()
         response = self.app.get(
-            url=url_for(controller='api', action='create_slug'),
+            url=url_for(controller='api', action='is_slug_valid'),
             params={
-               'title': u'A New Title * With & Funny CHARacters',
+               'slug': u'A New Title * With & Funny CHARacters',
             },
             status=200,
         )
-        assert_equal(response.body, '{"valid": true, "name": "a-new-title-with-funny-characters"}')
+        assert_equal(response.body, '{"valid": true}')
+        assert_equal(response.header('Content-Type'), 'application/json;charset=utf-8')
+
+        response = self.app.get(
+            url=url_for(controller='api', action='is_slug_valid'),
+            params={
+               'slug': u'warandpeace',
+            },
+            status=200,
+        )
+        assert_equal(response.body, '{"valid": false}')
         assert_equal(response.header('Content-Type'), 'application/json;charset=utf-8')
 
     def test_tag_autocomplete(self):


--- a/ckan/tests/functional/test_group.py	Fri Oct 14 15:03:15 2011 +0100
+++ b/ckan/tests/functional/test_group.py	Fri Oct 14 23:06:51 2011 +0100
@@ -115,7 +115,7 @@
     def test_new_page(self):
         offset = url_for(controller='group', action='new')
         res = self.app.get(offset, extra_environ={'REMOTE_USER': 'russianfan'})
-        assert 'Create a new group' in res, res
+        assert 'Add A Group' in res, res
 
 
 class TestEdit(FunctionalTestCase):
@@ -247,10 +247,10 @@
         group_title = u'Test Title'
         group_description = u'A Description'
 
-        # Open 'new group' page
+        # Open 'Add A Group' page
         offset = url_for(controller='group', action='new')
         res = self.app.get(offset, status=200, extra_environ={'REMOTE_USER': 'russianfan'})
-        assert 'New Group' in res, res
+        assert 'Add A Group' in res, res
         fv = res.forms['group-edit']
         assert fv[prefix+'name'].value == '', fv.fields
         assert fv[prefix+'title'].value == ''
@@ -282,7 +282,7 @@
         group_name = u'testgrp1'
         offset = url_for(controller='group', action='new')
         res = self.app.get(offset, status=200, extra_environ={'REMOTE_USER': 'russianfan'})
-        assert 'New Group' in res, res
+        assert 'Add A Group' in res, res
         fv = res.forms['group-edit']
         assert fv[prefix+'name'].value == '', fv.fields
         fv[prefix+'name'] = group_name
@@ -296,7 +296,7 @@
         group_name = u'testgrp1'
         offset = url_for(controller='group', action='new')
         res = self.app.get(offset, status=200, extra_environ={'REMOTE_USER': 'russianfan'})
-        assert 'New Group' in res, res
+        assert 'Add A Group' in res, res
         fv = res.forms['group-edit']
         assert fv[prefix+'name'].value == '', fv.fields
         fv[prefix+'name'] = group_name


--- a/ckan/tests/functional/test_package.py	Fri Oct 14 15:03:15 2011 +0100
+++ b/ckan/tests/functional/test_package.py	Fri Oct 14 23:06:51 2011 +0100
@@ -1187,7 +1187,7 @@
         fv[prefix+'title'] = pkgtitle
         res = fv.submit('save')
         assert 'Error' in res, res
-        assert 'Dataset name already exists in database' in res, res
+        assert 'That URL is already in use.' in res, res
         self._assert_form_errors(res)
         
     def test_missing_fields(self):


--- a/ckan/tests/lib/test_dictization_schema.py	Fri Oct 14 15:03:15 2011 +0100
+++ b/ckan/tests/lib/test_dictization_schema.py	Fri Oct 14 23:06:51 2011 +0100
@@ -102,9 +102,9 @@
         converted_data, errors = validate(data, default_package_schema(), context)
 
         assert errors == {
-            'name': [u'Dataset name already exists in database'],
-            'resources': [{},
-                          {'url': [u'Missing value']}]
+            'name': [u'That URL is already in use.'],
+            #'resources': [{}
+            #              {'name': [u'That URL is already in use.']}]
         }, pformat(errors)
 
         data["id"] = package_id
@@ -112,14 +112,14 @@
         converted_data, errors = validate(data, default_package_schema(), context)
 
         assert errors == {
-            'resources': [{}, {'url': [u'Missing value']}]
+            #'resources': [{}, {'url': [u'Missing value']}]
         }, pformat(errors)
 
         data['name'] = '????jfaiofjioafjij'
         converted_data, errors = validate(data, default_package_schema(), context)
         assert errors == {
             'name': [u'Name must be purely lowercase alphanumeric (ascii) characters and these symbols: -_'],
-            'resources': [{}, {'url': [u'Missing value']}]
+            #'resources': [{}, {'url': [u'Missing value']}]
         },pformat(errors)
 
     def test_2_group_schema(self):


--- a/ckan/tests/lib/test_munge.py	Fri Oct 14 15:03:15 2011 +0100
+++ b/ckan/tests/lib/test_munge.py	Fri Oct 14 23:06:51 2011 +0100
@@ -3,16 +3,6 @@
 from ckan.lib.munge import munge_title_to_name, munge_name
 
 class TestMunge:
-    def test_munge_title_to_name(self):
-        def test_munge(title, expected_munge):
-            munge = munge_title_to_name(title)
-            assert_equal(munge, expected_munge)
-
-        test_munge('Adult participation in learning', 'adult-participation-in-learning')
-        test_munge('Alcohol Profile: Alcohol-specific hospital admission, males', 'alcohol-profile-alcohol-specific-hospital-admission-males')
-        test_munge('Age and limiting long-term illness by NS-SeC', 'age-and-limiting-long-term-illness-by-ns-sec')
-        test_munge('Higher Education Statistics: HE qualifications obtained in the UK by level, mode of study, domicile, gender, class of first degree and subject area 2001/02', 'higher-education-statistics-he-qualifications-obtained-in-the-uk-by-level-mode-of-study-2001-02')        
-
     def test_munge_name(self):
         def test_munge(title, expected_munge):
             munge = munge_name(title)

Repository URL: https://bitbucket.org/okfn/ckan/

--

This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.




More information about the ckan-changes mailing list